diff --git a/boot.py b/boot.py index 5d092bcea..55075eade 100644 --- a/boot.py +++ b/boot.py @@ -76,6 +76,7 @@ from .plugin.tooling import LspCopyToClipboardFromBase64Command from .plugin.tooling import LspDumpBufferCapabilities from .plugin.tooling import LspDumpWindowConfigs +from .plugin.tooling import LspOnDoubleClickCommand from .plugin.tooling import LspParseVscodePackageJson from .plugin.tooling import LspTroubleshootServerCommand diff --git a/plugin/inlay_hint.py b/plugin/inlay_hint.py index d4d155b0e..552c8b95b 100644 --- a/plugin/inlay_hint.py +++ b/plugin/inlay_hint.py @@ -71,7 +71,6 @@ def inlay_hint_to_phantom(view: sublime.View, inlay_hint: InlayHint, session: Se def get_inlay_hint_html(view: sublime.View, inlay_hint: InlayHint, session: Session, phantom_uuid: str) -> str: - tooltip = format_inlay_hint_tooltip(inlay_hint.get("tooltip")) label = format_inlay_hint_label(inlay_hint, session, phantom_uuid) font = view.settings().get('font_face') or "monospace" html = """ @@ -91,12 +90,11 @@ def get_inlay_hint_html(view: sublime.View, inlay_hint: InlayHint, session: Sess text-decoration: none; }} -
+
{label}
""".format( - tooltip=tooltip, font=font, label=label ) @@ -112,40 +110,54 @@ def format_inlay_hint_tooltip(tooltip: Optional[Union[str, MarkupContent]]) -> s def format_inlay_hint_label(inlay_hint: InlayHint, session: Session, phantom_uuid: str) -> str: + tooltip = format_inlay_hint_tooltip(inlay_hint.get("tooltip")) result = "" can_resolve_inlay_hint = session.has_capability('inlayHintProvider.resolveProvider') label = inlay_hint['label'] - is_clickable = bool(inlay_hint.get('textEdits')) or can_resolve_inlay_hint + has_text_edits = bool(inlay_hint.get('textEdits')) + is_clickable = has_text_edits or can_resolve_inlay_hint if isinstance(label, str): if is_clickable: - inlay_hint_click_command = sublime.command_url('lsp_inlay_hint_click', { - 'session_name': session.config.name, - 'inlay_hint': cast(dict, inlay_hint), - 'phantom_uuid': phantom_uuid + inlay_hint_click_command = sublime.command_url('lsp_on_double_click', { + 'command': 'lsp_inlay_hint_click', + 'args': { + 'session_name': session.config.name, + 'inlay_hint': cast(dict, inlay_hint), + 'phantom_uuid': phantom_uuid + } }) result += ''.format(command=inlay_hint_click_command) - result += html.escape(label) + instruction_text = '\nDouble-click to insert' if has_text_edits else "" + result += '{value}'.format( + tooltip=(tooltip + instruction_text).strip(), + value=html.escape(label) + ) if is_clickable: result += "" return result for label_part in label: value = "" - is_clickable = is_clickable or bool(label_part.get('command')) - if is_clickable: - inlay_hint_click_command = sublime.command_url('lsp_inlay_hint_click', { - 'session_name': session.config.name, - 'inlay_hint': cast(dict, inlay_hint), - 'phantom_uuid': phantom_uuid, - 'label_part': cast(dict, label_part) + tooltip = format_inlay_hint_tooltip(label_part.get("tooltip")) + has_command = bool(label_part.get('command')) + if has_command: + inlay_hint_click_command = sublime.command_url('lsp_on_double_click', { + 'command': 'lsp_inlay_hint_click', + 'args': { + 'session_name': session.config.name, + 'inlay_hint': cast(dict, inlay_hint), + 'phantom_uuid': phantom_uuid, + 'label_part': cast(dict, label_part) + } }) value += ''.format(command=inlay_hint_click_command) value += html.escape(label_part['value']) - if is_clickable: + if has_command: value += "" # InlayHintLabelPart.location is not supported + instruction_text = '\nDouble-click to execute' if has_command else "" result += "{value}".format( - tooltip=format_inlay_hint_tooltip(label_part.get("tooltip")), + tooltip=(tooltip + instruction_text).strip(), value=value ) return result diff --git a/plugin/tooling.py b/plugin/tooling.py index ea026813c..71592ad57 100644 --- a/plugin/tooling.py +++ b/plugin/tooling.py @@ -535,3 +535,26 @@ def on_transport_close(self, exit_code: int, exception: Optional[Exception]) -> self._transport = None output = str(exception) if exception else '\n'.join(self._stderr_lines).rstrip() sublime.set_timeout(lambda: self._on_close(self._resolved_command, output, exit_code)) + + +class LspOnDoubleClickCommand(sublime_plugin.TextCommand): + click_count = 0 + prev_command = None # type: Optional[str] + prev_args = None # type: Optional[Dict[Any, Any]] + + def run(self, edit: sublime.Edit, command: str, args: Dict[Any, Any]) -> None: + if self.prev_command != command or self.prev_args != args: + self.click_count = 0 + self.prev_command = command + self.prev_args = args + self.click_count += 1 + if self.click_count == 2: + self.view.run_command(command, args) + self.reset() + return + sublime.set_timeout(self.reset, 500) + + def reset(self) -> None: + self.click_count = 0 + self.prev_command = None + self.prev_args = None