Skip to content

Commit da960d5

Browse files
authored
Tweaks for signature help popup (#2006)
- Add contextSupport - Add support for `activeParameter` property on `SignatureInformation` - Allow color schemes to adjust color of currently highlighted parameter - Small tweaks regarding code style - Don't close popup while user is typing parameters
1 parent 2ac87a7 commit da960d5

File tree

5 files changed

+43
-31
lines changed

5 files changed

+43
-31
lines changed

docs/src/customization.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ The color scheme rule only works if the "background" color is different from the
200200
| ----- | ----------- |
201201
| `entity.name.function.sighelp.lsp` | Function name in the signature help popup |
202202
| `variable.parameter.sighelp.lsp` | Function argument in the signature help popup |
203+
| `variable.parameter.sighelp.active.lsp` | Function argument which is currently highlighted in the signature help popup |
203204

204205
### Annotations
205206

plugin/core/protocol.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ class SemanticTokenModifiers:
228228
SignatureInformation = TypedDict('SignatureInformation', {
229229
'label': str,
230230
'documentation': Union[str, Dict[str, str]],
231-
'parameters': List[ParameterInformation]
231+
'parameters': List[ParameterInformation],
232+
'activeParameter': int
232233
}, total=False)
233234

234235

plugin/core/sessions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,9 @@ def get_initialize_params(variables: Dict[str, str], workspace_folders: List[Wor
254254
},
255255
"signatureHelp": {
256256
"dynamicRegistration": True,
257+
"contextSupport": True,
257258
"signatureInformation": {
259+
"activeParameterSupport": True,
258260
"documentationFormat": ["markdown", "plaintext"],
259261
"parameterInformation": {
260262
"labelOffsetSupport": True

plugin/core/signature_help.py

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from .logging import debug
22
from .protocol import SignatureHelp
3-
from .protocol import SignatureHelpContext
43
from .protocol import SignatureInformation
54
from .registry import LspTextCommand
65
from .typing import Optional, List
@@ -66,26 +65,18 @@ def render(self, view: sublime.View) -> str:
6665
except IndexError:
6766
return ""
6867
formatted = [] # type: List[str]
69-
intro = self._render_intro()
70-
if intro:
71-
formatted.append(intro)
68+
if self.has_multiple_signatures():
69+
formatted.append(self._render_intro())
7270
formatted.extend(self._render_label(view, signature))
7371
formatted.extend(self._render_docs(view, signature))
7472
return "".join(formatted)
7573

76-
def context(self, trigger_kind: int, trigger_character: str, is_retrigger: bool) -> SignatureHelpContext:
74+
def active_signature_help(self) -> SignatureHelp:
7775
"""
7876
Extract the state out of this state machine to send back to the language server.
79-
80-
XXX: Currently unused. Revisit this some time in the future.
8177
"""
8278
self._state["activeSignature"] = self._active_signature_index
83-
return {
84-
"triggerKind": trigger_kind,
85-
"triggerCharacter": trigger_character,
86-
"isRetrigger": is_retrigger,
87-
"activeSignatureHelp": self._state
88-
}
79+
return self._state
8980

9081
def has_multiple_signatures(self) -> bool:
9182
"""Does the current signature help state contain more than one overload?"""
@@ -96,18 +87,13 @@ def select_signature(self, forward: bool) -> None:
9687
new_index = self._active_signature_index + (1 if forward else -1)
9788
self._active_signature_index = max(0, min(new_index, len(self._signatures) - 1))
9889

99-
def active_signature(self) -> SignatureInformation:
100-
return self._signatures[self._active_signature_index]
101-
102-
def _render_intro(self) -> Optional[str]:
103-
if len(self._signatures) > 1:
104-
fmt = '<p><div style="font-size: 0.9rem"><b>{}</b> of <b>{}</b> overloads ' + \
105-
"(use ↑ ↓ to navigate, press Esc to hide):</div></p>"
106-
return fmt.format(
107-
self._active_signature_index + 1,
108-
len(self._signatures),
109-
)
110-
return None
90+
def _render_intro(self) -> str:
91+
fmt = '<p><div style="font-size: 0.9rem"><b>{}</b> of <b>{}</b> overloads ' + \
92+
"(use ↑ ↓ to navigate, press Esc to hide):</div></p>"
93+
return fmt.format(
94+
self._active_signature_index + 1,
95+
len(self._signatures),
96+
)
11197

11298
def _render_label(self, view: sublime.View, signature: SignatureInformation) -> List[str]:
11399
formatted = [] # type: List[str]
@@ -118,6 +104,7 @@ def _render_label(self, view: sublime.View, signature: SignatureInformation) ->
118104
parameters = signature.get("parameters")
119105
if parameters:
120106
prev, start, end = 0, 0, 0
107+
active_parameter_index = signature.get("activeParameter", self._active_parameter_index)
121108
for i, param in enumerate(parameters):
122109
rawlabel = param["label"]
123110
if isinstance(rawlabel, list):
@@ -136,7 +123,7 @@ def _render_label(self, view: sublime.View, signature: SignatureInformation) ->
136123
end = start + len(rawlabel)
137124
if prev < start:
138125
formatted.append(_function(view, label[prev:start]))
139-
formatted.append(_parameter(view, label[start:end], i == self._active_parameter_index))
126+
formatted.append(_parameter(view, label[start:end], i == active_parameter_index))
140127
prev = end
141128
if end < len(label):
142129
formatted.append(_function(view, label[end:]))
@@ -164,7 +151,7 @@ def _parameter_documentation(self, view: sublime.View, signature: SignatureInfor
164151
if not parameters:
165152
return None
166153
try:
167-
parameter = parameters[self._active_parameter_index]
154+
parameter = parameters[signature.get("activeParameter", self._active_parameter_index)]
168155
except IndexError:
169156
return None
170157
documentation = parameter.get("documentation")
@@ -186,7 +173,8 @@ def _function(view: sublime.View, content: str) -> str:
186173

187174

188175
def _parameter(view: sublime.View, content: str, emphasize: bool) -> str:
189-
return _wrap_with_scope_style(view, content, "variable.parameter.sighelp.lsp", emphasize)
176+
scope = "variable.parameter.sighelp.active.lsp" if emphasize else "variable.parameter.sighelp.lsp"
177+
return _wrap_with_scope_style(view, content, scope, emphasize)
190178

191179

192180
def _wrap_with_scope_style(view: sublime.View, content: str, scope: str, emphasize: bool) -> str:

plugin/documents.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from .core.protocol import Range
1515
from .core.protocol import Request
1616
from .core.protocol import SignatureHelp
17+
from .core.protocol import SignatureHelpContext
18+
from .core.protocol import SignatureHelpTriggerKind
1719
from .core.registry import best_session
1820
from .core.registry import windows
1921
from .core.sessions import AbstractViewListener
@@ -466,10 +468,28 @@ def do_signature_help_async(self, manual: bool) -> None:
466468
last_char = previous_non_whitespace_char(self.view, pos)
467469
if manual or last_char in triggers:
468470
self.purge_changes_async()
469-
params = text_document_position_params(self.view, pos)
471+
position_params = text_document_position_params(self.view, pos)
472+
context_params = {} # type: SignatureHelpContext
473+
if manual:
474+
context_params["triggerKind"] = SignatureHelpTriggerKind.Invoked
475+
else:
476+
context_params["triggerKind"] = SignatureHelpTriggerKind.TriggerCharacter
477+
context_params["triggerCharacter"] = last_char
478+
context_params["isRetrigger"] = self._sighelp is not None
479+
if self._sighelp:
480+
context_params["activeSignatureHelp"] = self._sighelp.active_signature_help()
481+
params = {
482+
"textDocument": position_params["textDocument"],
483+
"position": position_params["position"],
484+
"context": context_params
485+
}
470486
language_map = session.markdown_language_id_to_st_syntax_map()
471487
request = Request.signatureHelp(params, self.view)
472488
session.send_request_async(request, lambda resp: self._on_signature_help(resp, pos, language_map))
489+
elif self.view.match_selector(pos, "meta.function-call.arguments"):
490+
# Don't force close the signature help popup while the user is typing the parameters.
491+
# See also: https://github.com/sublimehq/sublime_text/issues/5518
492+
pass
473493
else:
474494
# TODO: Refactor popup usage to a common class. We now have sigHelp, completionDocs, hover, and diags
475495
# all using a popup. Most of these systems assume they have exclusive access to a popup, while in
@@ -510,7 +530,7 @@ def _show_sighelp_popup(self, content: str, point: int) -> None:
510530
show_lsp_popup(
511531
self.view,
512532
content,
513-
flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY | sublime.COOPERATE_WITH_AUTO_COMPLETE,
533+
flags=sublime.COOPERATE_WITH_AUTO_COMPLETE,
514534
location=point,
515535
on_hide=self._on_sighelp_hide,
516536
on_navigate=self._on_sighelp_navigate)

0 commit comments

Comments
 (0)