diff --git a/plugin/hover.py b/plugin/hover.py
index 69956792a..4de0e05d4 100644
--- a/plugin/hover.py
+++ b/plugin/hover.py
@@ -20,6 +20,7 @@
from .core.sessions import SessionBufferProtocol
from .core.settings import userprefs
from .core.typing import List, Optional, Dict, Tuple, Sequence, Union
+from .core.url import parse_uri
from .core.views import diagnostic_severity
from .core.views import first_selection_region
from .core.views import format_code_actions_for_quick_panel
@@ -38,7 +39,7 @@
from .core.views import unpack_href_location
from .core.views import update_lsp_popup
from .session_view import HOVER_HIGHLIGHT_KEY
-import functools
+from functools import partial
import html
import sublime
@@ -123,7 +124,7 @@ def run(
hover_point = temp_point
self._base_dir = wm.get_project_path(self.view.file_name() or "")
self._hover_responses = [] # type: List[Tuple[Hover, Optional[MarkdownLangMap]]]
- self._document_link = ('', False, None) # type: Tuple[str, bool, Optional[sublime.Region]]
+ self._document_links = [] # type: List[DocumentLink]
self._actions_by_config = [] # type: List[CodeActionsByConfigName]
self._diagnostics_by_config = [] # type: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]]
# TODO: For code actions it makes more sense to use the whole selection under mouse (if available)
@@ -157,9 +158,7 @@ def request_symbol_hover_async(self, listener: AbstractViewListener, point: int)
Request("textDocument/hover", document_position, self.view)
))
language_maps.append(session.markdown_language_id_to_st_syntax_map())
-
- continuation = functools.partial(self._on_all_settled, listener, point, language_maps)
- Promise.all(hover_promises).then(continuation)
+ Promise.all(hover_promises).then(partial(self._on_all_settled, listener, point, language_maps))
def _create_hover_request(
self, session: Session, point: int
@@ -206,8 +205,7 @@ def request_document_link_async(self, listener: AbstractViewListener, point: int
link_promises.append(sv.session.send_request_task(Request.resolveDocumentLink(link, sv.view)).then(
lambda link: self._on_resolved_link(sv.session_buffer, link)))
if link_promises:
- continuation = functools.partial(self._on_all_document_links_resolved, listener, point)
- Promise.all(link_promises).then(continuation)
+ Promise.all(link_promises).then(partial(self._on_all_document_links_resolved, listener, point))
def _on_resolved_link(self, session_buffer: SessionBufferProtocol, link: DocumentLink) -> DocumentLink:
session_buffer.update_document_link(link)
@@ -216,20 +214,7 @@ def _on_resolved_link(self, session_buffer: SessionBufferProtocol, link: Documen
def _on_all_document_links_resolved(
self, listener: AbstractViewListener, point: int, links: List[DocumentLink]
) -> None:
- contents = []
- link_has_standard_tooltip = True
- for link in links:
- target = link.get("target")
- if not target:
- continue
- title = link.get("tooltip") or "Follow link"
- if title != "Follow link":
- link_has_standard_tooltip = False
- contents.append('{}'.format(html.escape(target), html.escape(title)))
- if len(contents) > 1:
- link_has_standard_tooltip = False
- link_range = range_to_region(links[0]["range"], self.view) if links else None
- self._document_link = ('
'.join(contents) if contents else '', link_has_standard_tooltip, link_range)
+ self._document_links = links
self.show_hover(listener, point, only_diagnostics=False)
def _handle_code_actions(
@@ -248,6 +233,26 @@ def symbol_actions_content(self, listener: AbstractViewListener, point: int) ->
actions = [lk.link(point, self.view) for lk in link_kinds if self.provider_exists(listener, lk)]
return " | ".join(actions) if actions else ""
+ def link_content_and_range(self) -> Tuple[str, Optional[sublime.Region]]:
+ if len(self._document_links) > 1:
+ combined_region = range_to_region(self._document_links[0]["range"], self.view)
+ for link in self._document_links[1:]:
+ combined_region = combined_region.cover(range_to_region(link["range"], self.view))
+ if all(link.get("target") for link in self._document_links):
+ return 'Follow Link…', combined_region
+ else:
+ return "Follow Link…", combined_region
+ elif len(self._document_links) == 1:
+ link = self._document_links[0]
+ target = link.get("target")
+ label = "Follow Link" if link.get("target", "file:").startswith("file:") else "Open in Browser"
+ title = link.get("tooltip")
+ tooltip = ' title="{}"'.format(html.escape(title)) if title else ""
+ region = range_to_region(link["range"], self.view)
+ return '{}'.format(html.escape(target), tooltip, label) if target else label, region
+ else:
+ return "", None
+
def diagnostics_content(self) -> str:
formatted = []
for sb, diagnostics in self._diagnostics_by_config:
@@ -283,17 +288,15 @@ def show_hover(self, listener: AbstractViewListener, point: int, only_diagnostic
def _show_hover(self, listener: AbstractViewListener, point: int, only_diagnostics: bool) -> None:
hover_content = self.hover_content()
contents = self.diagnostics_content() + hover_content + code_actions_content(self._actions_by_config)
- link_content, link_has_standard_tooltip, link_range = self._document_link
+ link_content, link_range = self.link_content_and_range()
only_link_content = not bool(contents) and link_range is not None
prefs = userprefs()
if prefs.show_symbol_action_links and contents and not only_diagnostics and hover_content:
symbol_actions_content = self.symbol_actions_content(listener, point)
- if link_content and link_has_standard_tooltip:
+ if link_content:
if symbol_actions_content:
symbol_actions_content += ' | '
symbol_actions_content += link_content
- elif link_content:
- contents += '