From 0befb40d8cd4d8f9dbdccce1ae699e42a5a703d3 Mon Sep 17 00:00:00 2001 From: Janos Wortmann Date: Tue, 12 Nov 2024 19:25:40 +0100 Subject: [PATCH 1/5] Move region key strings into enum --- plugin/core/constants.py | 11 +++++++++-- plugin/documents.py | 5 +++-- plugin/hover.py | 6 +++--- plugin/references.py | 3 ++- plugin/session_buffer.py | 5 +++-- plugin/session_view.py | 13 ++++++------- tests/test_code_actions.py | 8 ++++---- 7 files changed, 30 insertions(+), 21 deletions(-) diff --git a/plugin/core/constants.py b/plugin/core/constants.py index 3793d3465..beae8df1c 100644 --- a/plugin/core/constants.py +++ b/plugin/core/constants.py @@ -4,6 +4,7 @@ from .protocol import DiagnosticSeverity from .protocol import DocumentHighlightKind from .protocol import SymbolKind +from .typing import StrEnum from typing import Tuple import sublime @@ -13,8 +14,14 @@ ST_VERSION = int(sublime.version()) -# Keys for View.add_regions -HOVER_HIGHLIGHT_KEY = 'lsp_hover_highlight' + +class RegionKey(StrEnum): + """ Key names for use with the `View.add_regions` method. """ + CODE_ACTION = 'lsp_code_action' + DOCUMENT_LINK = 'lsp_document_link' + HOVER_HIGHLIGHT = 'lsp_hover_highlight' + REFERENCE_HIGHLIGHT = 'lsp_reference_highlight' + # Setting keys CODE_LENS_ENABLED_KEY = 'lsp_show_code_lens' diff --git a/plugin/documents.py b/plugin/documents.py index 9dbf5d366..ded87dec2 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -6,6 +6,7 @@ from .core.constants import DOCUMENT_HIGHLIGHT_KIND_NAMES from .core.constants import DOCUMENT_HIGHLIGHT_KIND_SCOPES from .core.constants import HOVER_ENABLED_KEY +from .core.constants import RegionKey from .core.logging import debug from .core.open import open_in_browser from .core.panels import PanelName @@ -762,7 +763,7 @@ def _on_code_actions(self, responses: list[CodeActionsByConfigName]) -> None: annotations = [f"
{code_actions_link}
"] annotation_color = self.view.style_for_scope("region.bluish markup.accent.codeaction.lsp")["foreground"] self.view.add_regions( - SessionView.CODE_ACTIONS_KEY, regions, scope, icon, flags, annotations, annotation_color, + RegionKey.CODE_ACTION, regions, scope, icon, flags, annotations, annotation_color, on_navigate=self._on_code_actions_annotation_click ) @@ -771,7 +772,7 @@ def _on_code_actions_annotation_click(self, href: str) -> None: self.view.run_command('lsp_code_actions', {'code_actions_by_config': self._code_actions_for_selection}) def _clear_code_actions_annotation(self) -> None: - self.view.erase_regions(SessionView.CODE_ACTIONS_KEY) + self.view.erase_regions(RegionKey.CODE_ACTION) self._lightbulb_line = None def _on_navigate(self, href: str, point: int) -> None: diff --git a/plugin/hover.py b/plugin/hover.py index 703b6f782..4dd3841da 100644 --- a/plugin/hover.py +++ b/plugin/hover.py @@ -3,7 +3,7 @@ from .code_actions import CodeActionOrCommand from .code_actions import CodeActionsByConfigName from .core.constants import HOVER_ENABLED_KEY -from .core.constants import HOVER_HIGHLIGHT_KEY +from .core.constants import RegionKey from .core.constants import SHOW_DEFINITIONS_KEY from .core.open import lsp_range_from_uri_fragment from .core.open import open_file_uri @@ -303,7 +303,7 @@ def _show_hover(self, listener: AbstractViewListener, point: int, only_diagnosti if hover_range: _, flags = prefs.highlight_style_region_flags(prefs.hover_highlight_style) self.view.add_regions( - HOVER_HIGHLIGHT_KEY, + RegionKey.HOVER_HIGHLIGHT, regions=[hover_range], scope="region.cyanish markup.highlight.hover.lsp", flags=flags) @@ -316,7 +316,7 @@ def _show_hover(self, listener: AbstractViewListener, point: int, only_diagnosti flags=sublime.PopupFlags.HIDE_ON_MOUSE_MOVE_AWAY, location=point, on_navigate=lambda href: self._on_navigate(href, point), - on_hide=lambda: self.view.erase_regions(HOVER_HIGHLIGHT_KEY)) + on_hide=lambda: self.view.erase_regions(RegionKey.HOVER_HIGHLIGHT)) self._image_resolver = mdpopups.resolve_images( contents, mdpopups.worker_thread_resolver, partial(self._on_images_resolved, contents)) diff --git a/plugin/references.py b/plugin/references.py index d697e0c9a..19ca2b863 100644 --- a/plugin/references.py +++ b/plugin/references.py @@ -1,4 +1,5 @@ from __future__ import annotations +from .core.constants import RegionKey from .core.protocol import Location from .core.protocol import Point from .core.protocol import Request @@ -219,7 +220,7 @@ def _show_references_in_output_panel(self, word: str, session: Session, location # highlight all word occurrences regions = panel.find_all(rf"\b{word}\b") panel.add_regions( - 'ReferenceHighlight', + RegionKey.REFERENCE_HIGHLIGHT, regions, 'comment', flags=sublime.RegionFlags.DRAW_NO_FILL | sublime.RegionFlags.NO_UNDO diff --git a/plugin/session_buffer.py b/plugin/session_buffer.py index aaa21fb60..e0d4cb49f 100644 --- a/plugin/session_buffer.py +++ b/plugin/session_buffer.py @@ -1,5 +1,6 @@ from __future__ import annotations from .core.constants import DOCUMENT_LINK_FLAGS +from .core.constants import RegionKey from .core.constants import SEMANTIC_TOKEN_FLAGS from .core.protocol import ColorInformation from .core.protocol import Diagnostic @@ -465,10 +466,10 @@ def _redraw_document_links_async(self) -> None: regions = [range_to_region(link["range"], view) for link in self._document_links] for sv in self.session_views: sv.view.add_regions( - "lsp_document_link", regions, scope="markup.underline.link.lsp", flags=DOCUMENT_LINK_FLAGS) + RegionKey.DOCUMENT_LINK, regions, scope="markup.underline.link.lsp", flags=DOCUMENT_LINK_FLAGS) else: for sv in self.session_views: - sv.view.erase_regions("lsp_document_link") + sv.view.erase_regions(RegionKey.DOCUMENT_LINK) def get_document_link_at_point(self, view: sublime.View, point: int) -> DocumentLink | None: for link in self._document_links: diff --git a/plugin/session_view.py b/plugin/session_view.py index 7395df858..547a6f366 100644 --- a/plugin/session_view.py +++ b/plugin/session_view.py @@ -4,7 +4,7 @@ from .core.active_request import ActiveRequest from .core.constants import DOCUMENT_HIGHLIGHT_KIND_NAMES from .core.constants import HOVER_ENABLED_KEY -from .core.constants import HOVER_HIGHLIGHT_KEY +from .core.constants import RegionKey from .core.constants import REGIONS_INITIALIZE_FLAGS from .core.constants import SHOW_DEFINITIONS_KEY from .core.promise import Promise @@ -48,7 +48,6 @@ class SessionView: AC_TRIGGERS_KEY = "auto_complete_triggers" COMPLETION_PROVIDER_KEY = "completionProvider" TRIGGER_CHARACTERS_KEY = "completionProvider.triggerCharacters" - CODE_ACTIONS_KEY = "lsp_code_action" _session_buffers: WeakValueDictionary[tuple[int, int], SessionBuffer] = WeakValueDictionary() @@ -99,7 +98,7 @@ def on_before_remove(self) -> None: self.view.erase_regions(f"{self.diagnostics_key(severity, False)}_underline") self.view.erase_regions(f"{self.diagnostics_key(severity, True)}_icon") self.view.erase_regions(f"{self.diagnostics_key(severity, True)}_underline") - self.view.erase_regions("lsp_document_link") + self.view.erase_regions(RegionKey.DOCUMENT_LINK) self.session_buffer.remove_session_view(self) listener = self.listener() if listener: @@ -138,7 +137,7 @@ def _initialize_region_keys(self) -> None: document_highlight_style = userprefs().document_highlight_style hover_highlight_style = userprefs().hover_highlight_style line_modes = ["m", "s"] - self.view.add_regions(self.CODE_ACTIONS_KEY, r) # code actions lightbulb icon should always be on top + self.view.add_regions(RegionKey.CODE_ACTION, r) # code actions lightbulb icon should always be on top session_name = self.session.config.name for key in range(1, 100): keys.append(f"lsp_semantic_{session_name}_{key}") @@ -147,12 +146,12 @@ def _initialize_region_keys(self) -> None: for mode in line_modes: keys.append(f"lsp_highlight_{kind}{mode}") if hover_highlight_style in ("background", "fill"): - keys.append(HOVER_HIGHLIGHT_KEY) + keys.append(RegionKey.HOVER_HIGHLIGHT) for severity in range(1, 5): for mode in line_modes: for tag in range(1, 3): keys.append(f"lsp{session_name}d{mode}{severity}_tags_{tag}") - keys.append("lsp_document_link") + keys.append(RegionKey.DOCUMENT_LINK) for severity in range(1, 5): for mode in line_modes: keys.append(f"lsp{session_name}d{mode}{severity}_icon") @@ -164,7 +163,7 @@ def _initialize_region_keys(self) -> None: for mode in line_modes: keys.append(f"lsp_highlight_{kind}{mode}") if hover_highlight_style in ("underline", "stippled"): - keys.append(HOVER_HIGHLIGHT_KEY) + keys.append(RegionKey.HOVER_HIGHLIGHT) for key in keys: self.view.add_regions(key, r, flags=REGIONS_INITIALIZE_FLAGS) self._diagnostic_annotations.initialize_region_keys() diff --git a/tests/test_code_actions.py b/tests/test_code_actions.py index dec107784..c60aa9043 100644 --- a/tests/test_code_actions.py +++ b/tests/test_code_actions.py @@ -1,11 +1,11 @@ from __future__ import annotations from copy import deepcopy from LSP.plugin.code_actions import get_matching_on_save_kinds, kinds_include_kind +from LSP.plugin.core.constants import RegionKey from LSP.plugin.core.protocol import Point, Range from LSP.plugin.core.url import filename_to_uri from LSP.plugin.core.views import entire_content from LSP.plugin.documents import DocumentSyncListener -from LSP.plugin.session_view import SessionView from LSP.plugin.core.views import versioned_text_document_identifier from setup import TextDocumentTestCase from test_single_document import TEST_FILE_PATH @@ -304,7 +304,7 @@ def test_requests_with_diagnostics(self) -> Generator: self.assertEqual(params['range']['end']['line'], 1) self.assertEqual(params['range']['end']['character'], 1) self.assertEqual(len(params['context']['diagnostics']), 2) - annotations_range = self.view.get_regions(SessionView.CODE_ACTIONS_KEY) + annotations_range = self.view.get_regions(RegionKey.CODE_ACTION) self.assertEqual(len(annotations_range), 1) self.assertEqual(annotations_range[0].a, 3) self.assertEqual(annotations_range[0].b, 0) @@ -326,7 +326,7 @@ def test_requests_with_no_diagnostics(self) -> Generator: self.assertEqual(params['range']['end']['line'], 1) self.assertEqual(params['range']['end']['character'], 1) self.assertEqual(len(params['context']['diagnostics']), 0) - annotations_range = self.view.get_regions(SessionView.CODE_ACTIONS_KEY) + annotations_range = self.view.get_regions(RegionKey.CODE_ACTION) self.assertEqual(len(annotations_range), 1) self.assertEqual(annotations_range[0].a, 3) self.assertEqual(annotations_range[0].b, 0) @@ -344,7 +344,7 @@ def test_excludes_disabled_code_actions(self) -> Generator: self.view.run_command('lsp_selection_set', {"regions": [(0, 1)]}) # Select a yield 100 yield from self.await_message('textDocument/codeAction') - code_action_ranges = self.view.get_regions(SessionView.CODE_ACTIONS_KEY) + code_action_ranges = self.view.get_regions(RegionKey.CODE_ACTION) self.assertEqual(len(code_action_ranges), 0) def test_extends_range_to_include_diagnostics(self) -> Generator: From 356054a8a4de4cedf238b83cd2f10be9d01eef15 Mon Sep 17 00:00:00 2001 From: Janos Wortmann Date: Thu, 14 Nov 2024 09:31:00 +0100 Subject: [PATCH 2/5] List all commands in on_post_text_command explicitly --- plugin/documents.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index ded87dec2..8ac19579a 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -583,8 +583,9 @@ def on_post_text_command(self, command_name: str, args: dict[str, Any] | None) - sublime.set_timeout_async(lambda: self.do_signature_help_async(manual=True)) if not self.view.is_popup_visible(): return - if command_name in ["hide_auto_complete", "move", "commit_completion"] or 'delete' in command_name: - # hide the popup when `esc` or arrows are pressed pressed + if command_name in ("hide_auto_complete", "move", "commit_completion", "delete_word", "delete_to_mark", + "left_delete", "right_delete"): + # hide the popup when `esc` or arrows are pressed self.view.hide_popup() @requires_session From a1f3f21118d5b05164e45650a3baf67677e7a49c Mon Sep 17 00:00:00 2001 From: Janos Wortmann Date: Thu, 14 Nov 2024 09:43:36 +0100 Subject: [PATCH 3/5] Remove unnecessary cross-references in settings file --- LSP.sublime-settings | 2 -- 1 file changed, 2 deletions(-) diff --git a/LSP.sublime-settings b/LSP.sublime-settings index 4a5a7c141..6cb35033c 100644 --- a/LSP.sublime-settings +++ b/LSP.sublime-settings @@ -112,7 +112,6 @@ // When disabled, gutter markers are still drawn, unless "diagnostics_gutter_marker" // is set to "". // Diagnostics which span multiple lines are always drawn with the "box" style. - // See also: "show_multiline_diagnostics_highlights". "diagnostics_highlight_style": { "error": "squiggly", "warning": "squiggly", @@ -125,7 +124,6 @@ "diagnostics_gutter_marker": "sign", // Show diagnostics spanning multiple lines in the view (as outlines). - // See also: "diagnostics_highlight_style". "show_multiline_diagnostics_highlights": true, // --- Hover popup -------------------------------------------------------------------- From 77756f33613f738a77453a3ebffd18ad8b5c7ca9 Mon Sep 17 00:00:00 2001 From: Janos Wortmann Date: Fri, 15 Nov 2024 07:54:11 +0100 Subject: [PATCH 4/5] Remove unused constant --- plugin/documents.py | 2 -- plugin/hover.py | 1 - 2 files changed, 3 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index 8ac19579a..2d14fcd38 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -70,8 +70,6 @@ import webbrowser -SUBLIME_WORD_MASK = 515 - P = ParamSpec('P') R = TypeVar('R') diff --git a/plugin/hover.py b/plugin/hover.py index 4dd3841da..f88ee1d47 100644 --- a/plugin/hover.py +++ b/plugin/hover.py @@ -47,7 +47,6 @@ import sublime_plugin -SUBLIME_WORD_MASK = 515 SessionName = str ResolvedHover = Union[Hover, Error] From 4cbc6e80c2c60c7ab148b581404e662ccc409bad Mon Sep 17 00:00:00 2001 From: Janos Wortmann Date: Fri, 15 Nov 2024 07:59:25 +0100 Subject: [PATCH 5/5] Remove deprecated API function --- plugin/documents.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index 2d14fcd38..2cb449ced 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -983,7 +983,7 @@ def _register_async(self) -> None: def _on_view_updated_async(self) -> None: if self._should_format_on_paste: self._should_format_on_paste = False - self._format_on_paste_async() + sublime.get_clipboard_async(self._format_on_paste_async) self._code_lenses_debouncer_async.debounce( self._do_code_lenses_async, timeout_ms=self.code_lenses_debounce_time) first_region, _ = self._update_stored_selection_async() @@ -1017,8 +1017,7 @@ def _update_stored_selection_async(self) -> tuple[sublime.Region | None, bool]: self._stored_selection = selection return changed_first_region, True - def _format_on_paste_async(self) -> None: - clipboard_text = sublime.get_clipboard() + def _format_on_paste_async(self, clipboard_text: str) -> None: sel = self.view.sel() split_clipboard_text = clipboard_text.split('\n') multi_cursor_paste = len(split_clipboard_text) == len(sel) and len(sel) > 1