Skip to content

Commit 0ef280f

Browse files
authored
Show diagnostics popup when hovering over gutter icons (#2349)
1 parent 00ce15c commit 0ef280f

File tree

1 file changed

+46
-17
lines changed

1 file changed

+46
-17
lines changed

plugin/documents.py

+46-17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .completion import QueryCompletionsTask
55
from .core.constants import HOVER_ENABLED_KEY
66
from .core.logging import debug
7+
from .core.open import open_in_browser
78
from .core.panels import PanelName
89
from .core.protocol import Diagnostic
910
from .core.protocol import DiagnosticSeverity
@@ -27,6 +28,7 @@
2728
from .core.settings import userprefs
2829
from .core.signature_help import SigHelp
2930
from .core.types import basescope2languageid
31+
from .core.types import ClientConfig
3032
from .core.types import debounced
3133
from .core.types import DebouncerNonThreadSafe
3234
from .core.types import FEATURES_TIMEOUT
@@ -40,6 +42,7 @@
4042
from .core.views import DOCUMENT_HIGHLIGHT_KINDS
4143
from .core.views import first_selection_region
4244
from .core.views import format_code_actions_for_quick_panel
45+
from .core.views import format_diagnostic_for_html
4346
from .core.views import make_link
4447
from .core.views import MarkdownLangMap
4548
from .core.views import range_to_region
@@ -176,7 +179,8 @@ def _setup(self) -> None:
176179
self._stored_selection = []
177180
self._sighelp = None # type: Optional[SigHelp]
178181
self._lightbulb_line = None # type: Optional[int]
179-
self._actions_by_config = [] # type: List[CodeActionsByConfigName]
182+
self._diagnostics_for_selection = [] # type: List[Tuple[SessionBufferProtocol, List[Diagnostic]]]
183+
self._code_actions_for_selection = [] # type: List[CodeActionsByConfigName]
180184
self._registered = False
181185

182186
def _cleanup(self) -> None:
@@ -471,17 +475,40 @@ def on_hover(self, point: int, hover_zone: int) -> None:
471475
if hover_zone == sublime.HOVER_TEXT and window and window.settings().get(HOVER_ENABLED_KEY, True):
472476
self.view.run_command("lsp_hover", {"point": point})
473477
elif hover_zone == sublime.HOVER_GUTTER:
474-
# Lightbulb must be visible and at the same line
475-
if self._lightbulb_line != self.view.rowcol(point)[0]:
476-
return
477-
content = code_actions_content(self._actions_by_config)
478+
sublime.set_timeout_async(partial(self._on_hover_gutter_async, point))
479+
480+
def _on_hover_gutter_async(self, point: int) -> None:
481+
content = ''
482+
if self._lightbulb_line == self.view.rowcol(point)[0]:
483+
content += code_actions_content(self._code_actions_for_selection)
484+
if userprefs().show_diagnostics_severity_level:
485+
diagnostics_with_config = [] # type: List[Tuple[ClientConfig, Diagnostic]]
486+
diagnostics_by_session_buffer = [] # type: List[Tuple[SessionBufferProtocol, List[Diagnostic]]]
487+
max_severity_level = min(userprefs().show_diagnostics_severity_level, DiagnosticSeverity.Information)
488+
if userprefs().diagnostics_gutter_marker:
489+
diagnostics_by_session_buffer = self.diagnostics_intersecting_async(self.view.line(point))[0]
490+
elif content:
491+
diagnostics_by_session_buffer = self._diagnostics_for_selection
478492
if content:
479-
show_lsp_popup(
480-
self.view,
481-
content,
482-
flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY,
483-
location=point,
484-
on_navigate=lambda href: self._on_navigate(href, point))
493+
max_severity_level = userprefs().show_diagnostics_severity_level
494+
for sb, diagnostics in diagnostics_by_session_buffer:
495+
diagnostics_with_config.extend(
496+
(sb.session.config, diagnostic) for diagnostic in diagnostics
497+
if diagnostic_severity(diagnostic) <= max_severity_level
498+
)
499+
if diagnostics_with_config:
500+
diagnostics_with_config.sort(key=lambda d: diagnostic_severity(d[1]))
501+
content += '<div class="diagnostics">'
502+
for config, diagnostic in diagnostics_with_config:
503+
content += format_diagnostic_for_html(config, diagnostic)
504+
content += '</div>'
505+
if content:
506+
show_lsp_popup(
507+
self.view,
508+
content,
509+
flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY,
510+
location=point,
511+
on_navigate=lambda href: self._on_navigate(href, point))
485512

486513
def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[Tuple[str, dict]]:
487514
if command_name == "auto_complete":
@@ -638,13 +665,13 @@ def _on_sighelp_navigate(self, href: str) -> None:
638665
def _do_code_actions_async(self) -> None:
639666
if not self._stored_selection:
640667
return
641-
diagnostics_by_config, covering = self.diagnostics_intersecting_async(self._stored_selection[0])
668+
self._diagnostics_for_selection, covering = self.diagnostics_intersecting_async(self._stored_selection[0])
642669
actions_manager \
643-
.request_for_region_async(self.view, covering, diagnostics_by_config, manual=False) \
670+
.request_for_region_async(self.view, covering, self._diagnostics_for_selection, manual=False) \
644671
.then(self._on_code_actions)
645672

646673
def _on_code_actions(self, responses: List[CodeActionsByConfigName]) -> None:
647-
self._actions_by_config = responses
674+
self._code_actions_for_selection = responses
648675
action_count = 0
649676
first_action_title = ''
650677
for _, actions in responses:
@@ -678,8 +705,8 @@ def _on_code_actions(self, responses: List[CodeActionsByConfigName]) -> None:
678705
)
679706

680707
def _on_code_actions_annotation_click(self, href: str) -> None:
681-
if href == 'code-actions:' and self._actions_by_config:
682-
self.view.run_command('lsp_code_actions', {'code_actions_by_config': self._actions_by_config})
708+
if href == 'code-actions:' and self._code_actions_for_selection:
709+
self.view.run_command('lsp_code_actions', {'code_actions_by_config': self._code_actions_for_selection})
683710

684711
def _clear_code_actions_annotation(self) -> None:
685712
self.view.erase_regions(SessionView.CODE_ACTIONS_KEY)
@@ -688,7 +715,7 @@ def _clear_code_actions_annotation(self) -> None:
688715
def _on_navigate(self, href: str, point: int) -> None:
689716
if href.startswith('code-actions:'):
690717
_, config_name = href.split(":")
691-
actions = next(actions for name, actions in self._actions_by_config if name == config_name)
718+
actions = next(actions for name, actions in self._code_actions_for_selection if name == config_name)
692719
if len(actions) > 1:
693720
window = self.view.window()
694721
if window:
@@ -701,6 +728,8 @@ def _on_navigate(self, href: str, point: int) -> None:
701728
placeholder="Code actions")
702729
else:
703730
self.handle_code_action_select(config_name, actions, 0)
731+
else:
732+
open_in_browser(href)
704733

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

0 commit comments

Comments
 (0)