Skip to content

Commit

Permalink
Show diagnostics popup when hovering over gutter icons (#2349)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwortmann authored Nov 9, 2023
1 parent 00ce15c commit 0ef280f
Showing 1 changed file with 46 additions and 17 deletions.
63 changes: 46 additions & 17 deletions plugin/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .completion import QueryCompletionsTask
from .core.constants import HOVER_ENABLED_KEY
from .core.logging import debug
from .core.open import open_in_browser
from .core.panels import PanelName
from .core.protocol import Diagnostic
from .core.protocol import DiagnosticSeverity
Expand All @@ -27,6 +28,7 @@
from .core.settings import userprefs
from .core.signature_help import SigHelp
from .core.types import basescope2languageid
from .core.types import ClientConfig
from .core.types import debounced
from .core.types import DebouncerNonThreadSafe
from .core.types import FEATURES_TIMEOUT
Expand All @@ -40,6 +42,7 @@
from .core.views import DOCUMENT_HIGHLIGHT_KINDS
from .core.views import first_selection_region
from .core.views import format_code_actions_for_quick_panel
from .core.views import format_diagnostic_for_html
from .core.views import make_link
from .core.views import MarkdownLangMap
from .core.views import range_to_region
Expand Down Expand Up @@ -176,7 +179,8 @@ def _setup(self) -> None:
self._stored_selection = []
self._sighelp = None # type: Optional[SigHelp]
self._lightbulb_line = None # type: Optional[int]
self._actions_by_config = [] # type: List[CodeActionsByConfigName]
self._diagnostics_for_selection = [] # type: List[Tuple[SessionBufferProtocol, List[Diagnostic]]]
self._code_actions_for_selection = [] # type: List[CodeActionsByConfigName]
self._registered = False

def _cleanup(self) -> None:
Expand Down Expand Up @@ -471,17 +475,40 @@ def on_hover(self, point: int, hover_zone: int) -> None:
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
if self._lightbulb_line != self.view.rowcol(point)[0]:
return
content = code_actions_content(self._actions_by_config)
sublime.set_timeout_async(partial(self._on_hover_gutter_async, point))

def _on_hover_gutter_async(self, point: int) -> None:
content = ''
if self._lightbulb_line == self.view.rowcol(point)[0]:
content += code_actions_content(self._code_actions_for_selection)
if userprefs().show_diagnostics_severity_level:
diagnostics_with_config = [] # type: List[Tuple[ClientConfig, Diagnostic]]
diagnostics_by_session_buffer = [] # type: List[Tuple[SessionBufferProtocol, List[Diagnostic]]]
max_severity_level = min(userprefs().show_diagnostics_severity_level, DiagnosticSeverity.Information)
if userprefs().diagnostics_gutter_marker:
diagnostics_by_session_buffer = self.diagnostics_intersecting_async(self.view.line(point))[0]
elif content:
diagnostics_by_session_buffer = self._diagnostics_for_selection
if content:
show_lsp_popup(
self.view,
content,
flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY,
location=point,
on_navigate=lambda href: self._on_navigate(href, point))
max_severity_level = userprefs().show_diagnostics_severity_level
for sb, diagnostics in diagnostics_by_session_buffer:
diagnostics_with_config.extend(
(sb.session.config, diagnostic) for diagnostic in diagnostics
if diagnostic_severity(diagnostic) <= max_severity_level
)
if diagnostics_with_config:
diagnostics_with_config.sort(key=lambda d: diagnostic_severity(d[1]))
content += '<div class="diagnostics">'
for config, diagnostic in diagnostics_with_config:
content += format_diagnostic_for_html(config, diagnostic)
content += '</div>'
if content:
show_lsp_popup(
self.view,
content,
flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY,
location=point,
on_navigate=lambda href: self._on_navigate(href, point))

def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[Tuple[str, dict]]:
if command_name == "auto_complete":
Expand Down Expand Up @@ -638,13 +665,13 @@ def _on_sighelp_navigate(self, href: str) -> None:
def _do_code_actions_async(self) -> None:
if not self._stored_selection:
return
diagnostics_by_config, covering = self.diagnostics_intersecting_async(self._stored_selection[0])
self._diagnostics_for_selection, covering = self.diagnostics_intersecting_async(self._stored_selection[0])
actions_manager \
.request_for_region_async(self.view, covering, diagnostics_by_config, manual=False) \
.request_for_region_async(self.view, covering, self._diagnostics_for_selection, manual=False) \
.then(self._on_code_actions)

def _on_code_actions(self, responses: List[CodeActionsByConfigName]) -> None:
self._actions_by_config = responses
self._code_actions_for_selection = responses
action_count = 0
first_action_title = ''
for _, actions in responses:
Expand Down Expand Up @@ -678,8 +705,8 @@ def _on_code_actions(self, responses: List[CodeActionsByConfigName]) -> None:
)

def _on_code_actions_annotation_click(self, href: str) -> None:
if href == 'code-actions:' and self._actions_by_config:
self.view.run_command('lsp_code_actions', {'code_actions_by_config': self._actions_by_config})
if href == 'code-actions:' and self._code_actions_for_selection:
self.view.run_command('lsp_code_actions', {'code_actions_by_config': self._code_actions_for_selection})

def _clear_code_actions_annotation(self) -> None:
self.view.erase_regions(SessionView.CODE_ACTIONS_KEY)
Expand All @@ -688,7 +715,7 @@ def _clear_code_actions_annotation(self) -> None:
def _on_navigate(self, href: str, point: int) -> None:
if href.startswith('code-actions:'):
_, config_name = href.split(":")
actions = next(actions for name, actions in self._actions_by_config if name == config_name)
actions = next(actions for name, actions in self._code_actions_for_selection if name == config_name)
if len(actions) > 1:
window = self.view.window()
if window:
Expand All @@ -701,6 +728,8 @@ def _on_navigate(self, href: str, point: int) -> None:
placeholder="Code actions")
else:
self.handle_code_action_select(config_name, actions, 0)
else:
open_in_browser(href)

def handle_code_action_select(self, config_name: str, actions: List[CodeActionOrCommand], index: int) -> None:
if index == -1:
Expand Down

0 comments on commit 0ef280f

Please sign in to comment.