3
3
from .core .logging import debug
4
4
from .core .promise import Promise
5
5
from .core .protocol import Diagnostic
6
+ from .core .protocol import DocumentLink
6
7
from .core .protocol import Error
7
8
from .core .protocol import ExperimentalTextDocumentRangeParams
8
9
from .core .protocol import Hover
@@ -118,6 +119,7 @@ def run(
118
119
wm = windows .lookup (window )
119
120
self ._base_dir = wm .get_project_path (self .view .file_name () or "" )
120
121
self ._hover_responses = [] # type: List[Tuple[Hover, Optional[MarkdownLangMap]]]
122
+ self ._document_link_content = ('' , False )
121
123
self ._actions_by_config = {} # type: Dict[str, List[CodeActionOrCommand]]
122
124
self ._diagnostics_by_config = [] # type: Sequence[Tuple[SessionBufferProtocol, Sequence[Diagnostic]]]
123
125
# TODO: For code actions it makes more sense to use the whole selection under mouse (if available)
@@ -129,6 +131,8 @@ def run_async() -> None:
129
131
return
130
132
if not only_diagnostics :
131
133
self .request_symbol_hover_async (listener , hover_point )
134
+ if userprefs ().link_highlight_style in ("underline" , "none" ):
135
+ self .request_document_link_async (listener , hover_point )
132
136
self ._diagnostics_by_config , covering = listener .diagnostics_touching_point_async (
133
137
hover_point , userprefs ().show_diagnostics_severity_level )
134
138
if self ._diagnostics_by_config :
@@ -183,6 +187,46 @@ def _on_all_settled(
183
187
self ._hover_responses = hovers
184
188
self .show_hover (listener , point , only_diagnostics = False )
185
189
190
+ def request_document_link_async (self , listener : AbstractViewListener , point : int ) -> None :
191
+ link_promises = [] # type: List[Promise[DocumentLink]]
192
+ for sv in listener .session_views_async ():
193
+ if not sv .has_capability_async ("documentLinkProvider" ):
194
+ continue
195
+ link = sv .session_buffer .get_document_link_at_point (sv .view , point )
196
+ if link is None :
197
+ continue
198
+ target = link .get ("target" )
199
+ if target :
200
+ link_promises .append (Promise .resolve (link ))
201
+ elif sv .has_capability_async ("documentLinkProvider.resolveProvider" ):
202
+ link_promises .append (sv .session .send_request_task (Request .resolveDocumentLink (link , sv .view )).then (
203
+ lambda link : self ._on_resolved_link (sv .session_buffer , link )))
204
+ if link_promises :
205
+ continuation = functools .partial (self ._on_all_document_links_resolved , listener , point )
206
+ Promise .all (link_promises ).then (continuation )
207
+
208
+ def _on_resolved_link (self , session_buffer : SessionBufferProtocol , link : DocumentLink ) -> DocumentLink :
209
+ session_buffer .update_document_link (link )
210
+ return link
211
+
212
+ def _on_all_document_links_resolved (
213
+ self , listener : AbstractViewListener , point : int , links : List [DocumentLink ]
214
+ ) -> None :
215
+ contents = []
216
+ link_has_standard_tooltip = True
217
+ for link in links :
218
+ target = link .get ("target" )
219
+ if not target :
220
+ continue
221
+ title = link .get ("tooltip" ) or "Follow link"
222
+ if title != "Follow link" :
223
+ link_has_standard_tooltip = False
224
+ contents .append ('<a href="{}">{}</a>' .format (target , title ))
225
+ if len (contents ) > 1 :
226
+ link_has_standard_tooltip = False
227
+ self ._document_link_content = ('<br>' .join (contents ) if contents else '' , link_has_standard_tooltip )
228
+ self .show_hover (listener , point , only_diagnostics = False )
229
+
186
230
def handle_code_actions (
187
231
self ,
188
232
listener : AbstractViewListener ,
@@ -196,11 +240,8 @@ def provider_exists(self, listener: AbstractViewListener, link: LinkKind) -> boo
196
240
return bool (listener .session_async ('{}Provider' .format (link .lsp_name )))
197
241
198
242
def symbol_actions_content (self , listener : AbstractViewListener , point : int ) -> str :
199
- if userprefs ().show_symbol_action_links :
200
- actions = [lk .link (point , self .view ) for lk in link_kinds if self .provider_exists (listener , lk )]
201
- if actions :
202
- return '<div class="actions">' + " | " .join (actions ) + "</div>"
203
- return ""
243
+ actions = [lk .link (point , self .view ) for lk in link_kinds if self .provider_exists (listener , lk )]
244
+ return " | " .join (actions ) if actions else ""
204
245
205
246
def diagnostics_content (self ) -> str :
206
247
formatted = []
@@ -229,8 +270,16 @@ def show_hover(self, listener: AbstractViewListener, point: int, only_diagnostic
229
270
def _show_hover (self , listener : AbstractViewListener , point : int , only_diagnostics : bool ) -> None :
230
271
hover_content = self .hover_content ()
231
272
contents = self .diagnostics_content () + hover_content + code_actions_content (self ._actions_by_config )
232
- if contents and not only_diagnostics and hover_content :
233
- contents += self .symbol_actions_content (listener , point )
273
+ link_content , link_has_standard_tooltip = self ._document_link_content
274
+ if userprefs ().show_symbol_action_links and contents and not only_diagnostics and hover_content :
275
+ symbol_actions_content = self .symbol_actions_content (listener , point )
276
+ if link_content and link_has_standard_tooltip :
277
+ symbol_actions_content += ' | ' + link_content
278
+ elif link_content :
279
+ contents += '<div class="link with-padding">' + link_content + '</div>'
280
+ contents += '<div class="actions">' + symbol_actions_content + '</div>'
281
+ elif link_content :
282
+ contents += '<div class="{}">{}</div>' .format ('link with-padding' if contents else 'link' , link_content )
234
283
235
284
_test_contents .clear ()
236
285
_test_contents .append (contents ) # for testing only
0 commit comments