diff --git a/Main.sublime-menu b/Main.sublime-menu index 0b39db9c5..0b5d71bd1 100644 --- a/Main.sublime-menu +++ b/Main.sublime-menu @@ -159,6 +159,11 @@ { "caption": "LSP: Show Inlay Hints", "command": "lsp_toggle_inlay_hints" + }, + { + "caption": "LSP: Show Hover Popups", + "command": "lsp_toggle_hover_popups", + "checkbox": true } ] }, diff --git a/boot.py b/boot.py index 686215f2f..f16116d15 100644 --- a/boot.py +++ b/boot.py @@ -56,6 +56,7 @@ from .plugin.hierarchy import LspHierarchyToggleCommand from .plugin.hierarchy import LspTypeHierarchyCommand from .plugin.hover import LspHoverCommand +from .plugin.hover import LspToggleHoverPopupsCommand from .plugin.inlay_hint import LspInlayHintClickCommand from .plugin.inlay_hint import LspToggleInlayHintsCommand from .plugin.panels import LspClearLogPanelCommand diff --git a/plugin/core/constants.py b/plugin/core/constants.py new file mode 100644 index 000000000..188ea4910 --- /dev/null +++ b/plugin/core/constants.py @@ -0,0 +1,10 @@ +# TODO: Move all constants which are shared by multiple modules into this file, so that they can be imported without +# causing import loops + +# Keys for View.add_regions +HOVER_HIGHLIGHT_KEY = 'lsp_hover_highlight' + +# Setting keys +HOVER_ENABLED_KEY = 'lsp_show_hover_popups' +HOVER_PROVIDER_COUNT_KEY = 'lsp_hover_provider_count' +SHOW_DEFINITIONS_KEY = 'show_definitions' diff --git a/plugin/core/sessions.py b/plugin/core/sessions.py index 5d661c741..2e538f5b4 100644 --- a/plugin/core/sessions.py +++ b/plugin/core/sessions.py @@ -581,6 +581,9 @@ def start_code_lenses_async(self) -> None: def set_code_lenses_pending_refresh(self, needs_refresh: bool = True) -> None: ... + def reset_show_definitions(self) -> None: + ... + class SessionBufferProtocol(Protocol): diff --git a/plugin/documents.py b/plugin/documents.py index 167e4221e..33afd3a57 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -2,6 +2,7 @@ from .code_actions import CodeActionOrCommand from .code_actions import CodeActionsByConfigName from .completion import QueryCompletionsTask +from .core.constants import HOVER_ENABLED_KEY from .core.logging import debug from .core.panels import PanelName from .core.protocol import Diagnostic @@ -466,7 +467,8 @@ def on_query_context(self, key: str, operator: int, operand: Any, match_all: boo def on_hover(self, point: int, hover_zone: int) -> None: if self.view.is_popup_visible(): return - if hover_zone == sublime.HOVER_TEXT: + window = self.view.window() + if hover_zone == sublime.HOVER_TEXT and window and window.settings().get(HOVER_ENABLED_KEY, True): self.view.run_command("lsp_hover", {"point": point}) elif hover_zone == sublime.HOVER_GUTTER: # Lightbulb must be visible and at the same line diff --git a/plugin/hover.py b/plugin/hover.py index ee24e34ab..3b82e91fc 100644 --- a/plugin/hover.py +++ b/plugin/hover.py @@ -1,6 +1,10 @@ from .code_actions import actions_manager from .code_actions import CodeActionOrCommand from .code_actions import CodeActionsByConfigName +from .core.constants import HOVER_ENABLED_KEY +from .core.constants import HOVER_HIGHLIGHT_KEY +from .core.constants import HOVER_PROVIDER_COUNT_KEY +from .core.constants import SHOW_DEFINITIONS_KEY from .core.open import lsp_range_from_uri_fragment from .core.open import open_file_uri from .core.open import open_in_browser @@ -18,6 +22,7 @@ from .core.sessions import SessionBufferProtocol from .core.settings import userprefs from .core.typing import List, Optional, Dict, Tuple, Sequence, Union +from .core.typing import cast from .core.url import parse_uri from .core.views import diagnostic_severity from .core.views import first_selection_region @@ -35,12 +40,12 @@ from .core.views import text_document_position_params from .core.views import unpack_href_location from .core.views import update_lsp_popup -from .session_view import HOVER_HIGHLIGHT_KEY from functools import partial from urllib.parse import urlparse import html import mdpopups import sublime +import sublime_plugin SUBLIME_WORD_MASK = 515 @@ -385,3 +390,34 @@ def try_open_custom_uri_async(self, href: str) -> None: for session in self.sessions(): if session.try_open_uri_async(href, r) is not None: return + + +class LspToggleHoverPopupsCommand(sublime_plugin.WindowCommand): + + def is_enabled(self) -> bool: + view = self.window.active_view() + if view: + return self._has_hover_provider(view) + return False + + def is_checked(self) -> bool: + return bool(self.window.settings().get(HOVER_ENABLED_KEY, True)) + + def run(self) -> None: + enable = not self.is_checked() + self.window.settings().set(HOVER_ENABLED_KEY, enable) + sublime.set_timeout_async(partial(self._update_views_async, enable)) + + def _has_hover_provider(self, view: sublime.View) -> bool: + return cast(int, view.settings().get(HOVER_PROVIDER_COUNT_KEY, 0)) > 0 + + def _update_views_async(self, enable: bool) -> None: + window_manager = windows.lookup(self.window) + if not window_manager: + return + for session in window_manager.get_sessions(): + for session_view in session.session_views_async(): + if enable: + session_view.view.settings().set(SHOW_DEFINITIONS_KEY, False) + else: + session_view.reset_show_definitions() diff --git a/plugin/session_view.py b/plugin/session_view.py index 6a205b3aa..4044a375e 100644 --- a/plugin/session_view.py +++ b/plugin/session_view.py @@ -1,5 +1,9 @@ from .code_lens import CodeLensView from .core.active_request import ActiveRequest +from .core.constants import HOVER_ENABLED_KEY +from .core.constants import HOVER_HIGHLIGHT_KEY +from .core.constants import HOVER_PROVIDER_COUNT_KEY +from .core.constants import SHOW_DEFINITIONS_KEY from .core.promise import Promise from .core.protocol import CodeLens from .core.protocol import CodeLensExtended @@ -22,7 +26,6 @@ import sublime DIAGNOSTIC_TAG_VALUES = [v for (k, v) in DiagnosticTag.__dict__.items() if not k.startswith('_')] # type: List[int] -HOVER_HIGHLIGHT_KEY = "lsp_hover_highlight" class TagData: @@ -39,9 +42,7 @@ class SessionView: Holds state per session per view. """ - SHOW_DEFINITIONS_KEY = "show_definitions" HOVER_PROVIDER_KEY = "hoverProvider" - HOVER_PROVIDER_COUNT_KEY = "lsp_hover_provider_count" AC_TRIGGERS_KEY = "auto_complete_triggers" COMPLETION_PROVIDER_KEY = "completionProvider" TRIGGER_CHARACTERS_KEY = "completionProvider.triggerCharacters" @@ -224,20 +225,25 @@ def _apply_auto_complete_triggers( def _increment_hover_count(self) -> None: settings = self.view.settings() - count = settings.get(self.HOVER_PROVIDER_COUNT_KEY, 0) + count = settings.get(HOVER_PROVIDER_COUNT_KEY, 0) if isinstance(count, int): count += 1 - settings.set(self.HOVER_PROVIDER_COUNT_KEY, count) - settings.set(self.SHOW_DEFINITIONS_KEY, False) + settings.set(HOVER_PROVIDER_COUNT_KEY, count) + window = self.view.window() + if window and window.settings().get(HOVER_ENABLED_KEY, True): + settings.set(SHOW_DEFINITIONS_KEY, False) def _decrement_hover_count(self) -> None: settings = self.view.settings() - count = settings.get(self.HOVER_PROVIDER_COUNT_KEY) + count = settings.get(HOVER_PROVIDER_COUNT_KEY) if isinstance(count, int): count -= 1 if count == 0: - settings.erase(self.HOVER_PROVIDER_COUNT_KEY) - settings.set(self.SHOW_DEFINITIONS_KEY, True) + settings.erase(HOVER_PROVIDER_COUNT_KEY) + self.reset_show_definitions() + + def reset_show_definitions(self) -> None: + self.view.settings().erase(SHOW_DEFINITIONS_KEY) def get_uri(self) -> Optional[DocumentUri]: listener = self.listener()