@@ -2297,33 +2297,45 @@ def run_auto_complete(self):
2297
2297
2298
2298
2299
2299
class SignatureHelpListener (sublime_plugin .ViewEventListener ):
2300
+
2301
+ css = ".mdpopups .lsp_signature { margin: 4px; } .mdpopups p { margin: 0.1rem; }"
2302
+ wrapper_class = "lsp_signature"
2303
+
2300
2304
def __init__ (self , view ):
2301
2305
self .view = view
2302
- self .signature_help_triggers = None
2306
+ self ._initialized = False
2307
+ self ._signature_help_triggers = [] # type: List[str]
2308
+ self ._visible = False
2309
+ self ._language_id = ""
2310
+ self ._signatures = [] # type: List[Any]
2311
+ self ._active_signature = - 1
2303
2312
2304
2313
@classmethod
2305
2314
def is_applicable (cls , settings ):
2306
2315
syntax = settings .get ('syntax' )
2307
2316
return syntax and is_supported_syntax (syntax )
2308
2317
2309
- def initialize_triggers (self ):
2318
+ def initialize (self ):
2310
2319
client = client_for_view (self .view )
2311
2320
if client :
2312
2321
signatureHelpProvider = client .get_capability (
2313
2322
'signatureHelpProvider' )
2314
2323
if signatureHelpProvider :
2315
2324
self .signature_help_triggers = signatureHelpProvider .get (
2316
2325
'triggerCharacters' )
2317
- return
2318
2326
2319
- self .signature_help_triggers = []
2327
+ config = config_for_scope (self .view )
2328
+ if config :
2329
+ self ._language_id = config .languageId
2330
+
2331
+ self ._initialized = True
2320
2332
2321
2333
def on_modified_async (self ):
2322
2334
pos = self .view .sel ()[0 ].begin ()
2323
2335
last_char = self .view .substr (pos - 1 )
2324
2336
# TODO: this will fire too often, narrow down using scopes or regex
2325
- if self .signature_help_triggers is None :
2326
- self .initialize_triggers ()
2337
+ if not self ._initialized :
2338
+ self .initialize ()
2327
2339
2328
2340
if self .signature_help_triggers :
2329
2341
if last_char in self .signature_help_triggers :
@@ -2337,40 +2349,87 @@ def on_modified_async(self):
2337
2349
lambda response : self .handle_response (response , pos ))
2338
2350
else :
2339
2351
# TODO: this hides too soon.
2340
- if self .view . is_popup_visible () :
2352
+ if self ._visible :
2341
2353
self .view .hide_popup ()
2342
2354
2343
2355
def handle_response (self , response , point ):
2344
2356
if response is not None :
2345
- config = config_for_scope (self .view )
2346
- signatures = response .get ("signatures" )
2347
- activeSignature = response .get ("activeSignature" )
2348
- debug ("got signatures, active is" , len (signatures ), activeSignature )
2349
- if len (signatures ) > 0 and config :
2350
- signature = signatures [activeSignature ]
2351
- debug ("active signature" , signature )
2352
- formatted = []
2353
- formatted .append (
2354
- "```{}\n {}\n ```" .format (config .languageId , signature .get ('label' )))
2355
- params = signature .get ('parameters' )
2356
- if params :
2357
- for parameter in params :
2358
- paramDocs = parameter .get ('documentation' )
2359
- if paramDocs :
2360
- formatted .append ("**{}**\n " .format (parameter .get ('label' )))
2361
- formatted .append ("* *{}*\n " .format (paramDocs ))
2362
-
2363
- formatted .append (signature .get ('documentation' ))
2364
-
2365
- mdpopups .show_popup (
2366
- self .view ,
2367
- preserve_whitespace ("\n " .join (formatted )),
2368
- css = ".mdpopups .lsp_signature { margin: 4px; } .mdpopups p { margin: 0.1rem; }" ,
2369
- md = True ,
2370
- flags = sublime .HIDE_ON_MOUSE_MOVE_AWAY ,
2371
- location = point ,
2372
- wrapper_class = "lsp_signature" ,
2373
- max_width = 800 )
2357
+ self ._signatures = response .get ("signatures" , [])
2358
+ self ._active_signature = response .get ("activeSignature" , - 1 )
2359
+
2360
+ if self ._signatures :
2361
+ if not 0 <= self ._active_signature < len (self ._signatures ):
2362
+ debug ("activeSignature {} not a valid index for signatures length {}" .format (
2363
+ self ._active_signature , len (self ._signatures )))
2364
+ self ._active_signature = 0
2365
+ else :
2366
+ if self ._active_signature != - 1 :
2367
+ debug ("activeSignature should be -1 or null when no signatures are returned" )
2368
+ self ._active_signature = - 1
2369
+
2370
+ if len (self ._signatures ) > 0 :
2371
+ mdpopups .show_popup (self .view ,
2372
+ self ._build_popup_content (),
2373
+ css = self .__class__ .css ,
2374
+ md = True ,
2375
+ flags = sublime .HIDE_ON_MOUSE_MOVE_AWAY ,
2376
+ location = point ,
2377
+ wrapper_class = self .__class__ .wrapper_class ,
2378
+ max_width = 800 ,
2379
+ on_hide = self ._on_hide )
2380
+ self ._visible = True
2381
+
2382
+ def on_query_context (self , key , _ , operand , __ ):
2383
+ if key != "lsp.signature_help" :
2384
+ return False # Let someone else handle this keybinding.
2385
+ elif not self ._visible :
2386
+ return False # Let someone else handle this keybinding.
2387
+ elif len (self ._signatures ) < 2 :
2388
+ return False # Let someone else handle this keybinding.
2389
+ else :
2390
+ # We use the "operand" for the number -1 or +1. See the keybindings.
2391
+ new_index = self ._active_signature + operand
2392
+
2393
+ # clamp signature index
2394
+ new_index = max (0 , min (new_index , len (self ._signatures ) - 1 ))
2395
+
2396
+ # only update when changed
2397
+ if new_index != self ._active_signature :
2398
+ self ._active_signature = new_index
2399
+ mdpopups .update_popup (self .view ,
2400
+ self ._build_popup_content (),
2401
+ css = self .__class__ .css ,
2402
+ md = True ,
2403
+ wrapper_class = self .__class__ .wrapper_class )
2404
+
2405
+ return True # We handled this keybinding.
2406
+
2407
+ def _on_hide (self ):
2408
+ self ._visible = False
2409
+
2410
+ def _build_popup_content (self ) -> str :
2411
+ signature = self ._signatures [self ._active_signature ]
2412
+ formatted = []
2413
+
2414
+ if len (self ._signatures ) > 1 :
2415
+ signature_navigation = "**{}** of **{}** overloads (use the arrow keys to navigate):\n " .format (
2416
+ str (self ._active_signature + 1 ), str (len (self ._signatures )))
2417
+ formatted .append (signature_navigation )
2418
+
2419
+ label = "```{}\n {}\n ```" .format (self ._language_id , signature .get ('label' ))
2420
+ formatted .append (label )
2421
+
2422
+ params = signature .get ('parameters' )
2423
+ if params :
2424
+ for parameter in params :
2425
+ paramDocs = parameter .get ('documentation' , None )
2426
+ if paramDocs :
2427
+ formatted .append ("**{}**\n " .format (parameter .get ('label' )))
2428
+ formatted .append ("* *{}*\n " .format (paramDocs ))
2429
+ sigDocs = signature .get ('documentation' , None )
2430
+ if sigDocs :
2431
+ formatted .append (sigDocs )
2432
+ return preserve_whitespace ("\n " .join (formatted ))
2374
2433
2375
2434
2376
2435
def get_line_diagnostics (view , point ):
0 commit comments