diff --git a/boot.py b/boot.py index 0a23d5e5f..cd9fe15c5 100644 --- a/boot.py +++ b/boot.py @@ -10,7 +10,7 @@ from .plugin.color import LspColorPresentationCommand from .plugin.completion import LspCommitCompletionWithOppositeInsertMode from .plugin.completion import LspResolveDocsCommand -from .plugin.completion import LspSelectCompletionItemCommand +from .plugin.completion import LspSelectCompletionCommand from .plugin.configuration import LspDisableLanguageServerGloballyCommand from .plugin.configuration import LspDisableLanguageServerInProjectCommand from .plugin.configuration import LspEnableLanguageServerGloballyCommand diff --git a/plugin/completion.py b/plugin/completion.py index 68d43468d..4c915b9a7 100644 --- a/plugin/completion.py +++ b/plugin/completion.py @@ -90,7 +90,7 @@ def _on_completion_response_async( def _resolve_completions_async(self, responses: List[ResolvedCompletions]) -> None: if self._resolved: return - LspResolveDocsCommand.completions = {} + LspSelectCompletionCommand.completions = {} items = [] # type: List[sublime.CompletionItem] errors = [] # type: List[Error] flags = 0 # int @@ -117,7 +117,7 @@ def _resolve_completions_async(self, responses: List[ResolvedCompletions]) -> No elif isinstance(response, list): response_items = response response_items = sorted(response_items, key=lambda item: item.get("sortText") or item["label"]) - LspResolveDocsCommand.completions[session.config.name] = response_items + LspSelectCompletionCommand.completions[session.config.name] = response_items can_resolve_completion_items = session.has_capability('completionProvider.resolveProvider') config_name = session.config.name items.extend( @@ -150,12 +150,10 @@ def _resolve_task_async(self, completions: List[sublime.CompletionItem], flags: class LspResolveDocsCommand(LspTextCommand): - completions = {} # type: Dict[SessionName, List[CompletionItem]] - def run(self, edit: sublime.Edit, index: int, session_name: str, event: Optional[dict] = None) -> None: def run_async() -> None: - item = self.completions[session_name][index] + item = LspSelectCompletionCommand.completions[session_name][index] session = self.session_by_name(session_name, 'completionProvider.resolveProvider') if session: request = Request.resolveCompletionItem(item, self.view) @@ -218,8 +216,12 @@ def run(self, edit: sublime.Edit, event: Optional[dict] = None) -> None: LspCommitCompletionWithOppositeInsertMode.active = False -class LspSelectCompletionItemCommand(LspTextCommand): - def run(self, edit: sublime.Edit, item: CompletionItem, session_name: str) -> None: +class LspSelectCompletionCommand(LspTextCommand): + + completions = {} # type: Dict[SessionName, List[CompletionItem]] + + def run(self, edit: sublime.Edit, index: int, session_name: str) -> None: + item = LspSelectCompletionCommand.completions[session_name][index] text_edit = item.get("textEdit") if text_edit: new_text = text_edit["newText"].replace("\r", "") diff --git a/plugin/core/views.py b/plugin/core/views.py index a98f23dad..385cccb35 100644 --- a/plugin/core/views.py +++ b/plugin/core/views.py @@ -1030,22 +1030,21 @@ def format_completion( item: CompletionItem, index: int, can_resolve_completion_items: bool, session_name: str, view_id: int ) -> sublime.CompletionItem: # This is a hot function. Don't do heavy computations or IO in this function. - lsp_label = item['label'] lsp_label_details = item.get('labelDetails') or {} lsp_label_detail = lsp_label_details.get('detail') or "" lsp_label_description = lsp_label_details.get('description') or "" lsp_filter_text = item.get('filterText') or "" lsp_detail = (item.get('detail') or "").replace("\n", " ") - completion_kind = item.get('kind') kind = COMPLETION_KINDS.get(completion_kind, sublime.KIND_AMBIGUOUS) if completion_kind else sublime.KIND_AMBIGUOUS - details = [] # type: List[str] if can_resolve_completion_items or item.get('documentation'): - details.append(make_command_link( - 'lsp_resolve_docs', "More", {'index': index, 'session_name': session_name}, view_id=view_id)) - + # Not using "make_command_link" in a hot path to avoid slow json.dumps. + args = '{{"view_id":{},"command":"lsp_resolve_docs","args":{{"index":{},"session_name":"{}"}}}}'.format( + view_id, index, session_name) + href = 'subl:lsp_run_text_command_helper {}'.format(args) + details.append(make_link(href, 'More')) if lsp_label_detail and (lsp_label + lsp_label_detail).startswith(lsp_filter_text): trigger = lsp_label + lsp_label_detail annotation = lsp_label_description or lsp_detail @@ -1062,22 +1061,24 @@ def format_completion( details.append(html.escape(lsp_label + lsp_label_detail)) if lsp_label_description: details.append(html.escape(lsp_label_description)) - if item.get('deprecated') or CompletionItemTag.Deprecated in item.get('tags', []): annotation = "DEPRECATED - " + annotation if annotation else "DEPRECATED" - - insert_replace_support_html = get_insert_replace_support_html(item) - if insert_replace_support_html: - details.append(insert_replace_support_html) - - completion = sublime.CompletionItem.command_completion( - trigger=trigger, - command='lsp_select_completion_item', - args={"item": item, "session_name": session_name}, - annotation=annotation, - kind=kind, - details=" | ".join(details)) - if item.get('textEdit'): + text_edit = item.get('textEdit') + if text_edit and 'insert' in text_edit and 'replace' in text_edit: + insert_mode = userprefs().completion_insert_mode + oposite_insert_mode = 'Replace' if insert_mode == 'insert' else 'Insert' + command_url = "subl:lsp_commit_completion_with_opposite_insert_mode" + details.append("{}".format(command_url, oposite_insert_mode)) + completion = sublime.CompletionItem( + trigger, + annotation, + # Not using "sublime.format_command" in a hot path to avoid slow json.dumps. + 'lsp_select_completion {{"index":{},"session_name":"{}"}}'.format(index, session_name), + sublime.COMPLETION_FORMAT_COMMAND, + kind, + details=" | ".join(details) + ) + if text_edit: completion.flags = sublime.COMPLETION_FLAG_KEEP_PREFIX return completion @@ -1095,13 +1096,3 @@ def format_code_actions_for_quick_panel( if code_action.get('isPreferred', False): selected_index = idx return items, selected_index - - -def get_insert_replace_support_html(item: CompletionItem) -> Optional[str]: - text_edit = item.get('textEdit') - if text_edit and 'insert' in text_edit and 'replace' in text_edit: - insert_mode = userprefs().completion_insert_mode - oposite_insert_mode = 'Replace' if insert_mode == 'insert' else 'Insert' - command_url = sublime.command_url("lsp_commit_completion_with_opposite_insert_mode") - return "{}".format(command_url, oposite_insert_mode) - return None diff --git a/stubs/sublime.pyi b/stubs/sublime.pyi index 2b2a9aee4..9c4e45efd 100644 --- a/stubs/sublime.pyi +++ b/stubs/sublime.pyi @@ -63,6 +63,7 @@ INHIBIT_EXPLICIT_COMPLETIONS = ... # type: int INHIBIT_REORDER = ... # type: int DYNAMIC_COMPLETIONS = ... # type: int COMPLETION_FLAG_KEEP_PREFIX = ... # type: int +COMPLETION_FORMAT_COMMAND = ... # type: int DIALOG_CANCEL = ... # type: int DIALOG_YES = ... # type: int DIALOG_NO = ... # type: int