From 18f4f2143a04632ebc5bb50b121333a4e0c62f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Mon, 22 Jan 2024 21:59:15 +0100 Subject: [PATCH 01/19] add format on paste --- LSP.sublime-settings | 3 +++ plugin/core/types.py | 2 ++ plugin/documents.py | 29 ++++++++++++++++++++++++++++- sublime-package.json | 5 +++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/LSP.sublime-settings b/LSP.sublime-settings index baf277228..ace2d1301 100644 --- a/LSP.sublime-settings +++ b/LSP.sublime-settings @@ -7,6 +7,9 @@ // --- Document Formatting ------------------------------------------------------------ + // Run the server's documentRangeFormattingProvider (if supported) on the pasted text. + "format_on_paste": false, + // Run the server's formatProvider (if supported) on a file before saving. // This option is also supported in syntax-specific settings and/or in the // "settings" section of project files. diff --git a/plugin/core/types.py b/plugin/core/types.py index 7fac717c2..4709a7253 100644 --- a/plugin/core/types.py +++ b/plugin/core/types.py @@ -205,6 +205,7 @@ class Settings: diagnostics_panel_include_severity_level = cast(int, None) disabled_capabilities = cast(List[str], None) document_highlight_style = cast(str, None) + format_on_paste = cast(bool, None) hover_highlight_style = cast(str, None) inhibit_snippet_completions = cast(bool, None) inhibit_word_completions = cast(bool, None) @@ -250,6 +251,7 @@ def r(name: str, default: Union[bool, int, str, list, dict]) -> None: r("diagnostics_panel_include_severity_level", 4) r("disabled_capabilities", []) r("document_highlight_style", "underline") + r("format_on_paste", False) r("hover_highlight_style", "") r("initially_folded", []) r("link_highlight_style", "underline") diff --git a/plugin/documents.py b/plugin/documents.py index 49653a875..f5e3cf913 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -170,6 +170,7 @@ def on_change() -> None: self._registration = SettingsRegistration(view.settings(), on_change=on_change) self._completions_task = None # type: Optional[QueryCompletionsTask] self._stored_selection = [] # type: List[sublime.Region] + self._did_paste = False self._setup() def __del__(self) -> None: @@ -528,7 +529,9 @@ def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[T return None def on_post_text_command(self, command_name: str, args: Optional[Dict[str, Any]]) -> None: - if command_name in ("next_field", "prev_field") and args is None: + if command_name == 'paste' and userprefs().format_on_paste: + self._did_paste = True + elif command_name in ("next_field", "prev_field") and args is None: sublime.set_timeout_async(lambda: self.do_signature_help_async(manual=True)) if not self.view.is_popup_visible(): return @@ -936,6 +939,9 @@ def _on_view_updated_async(self) -> None: self._when_selection_remains_stable_async( self._do_highlights_async, first_region, after_ms=self.highlights_debounce_time) self.do_signature_help_async(manual=False) + if self._did_paste: + self._did_paste = False + self._format_on_paste_async() def _update_stored_selection_async(self) -> Tuple[Optional[sublime.Region], bool]: """ @@ -959,6 +965,27 @@ def _update_stored_selection_async(self) -> Tuple[Optional[sublime.Region], bool self._stored_selection = selection return changed_first_region, True + def _format_on_paste_async(self) -> None: + self.purge_changes_async() + clipboard_text = sublime.get_clipboard() + sel = self.view.sel() + split_clipboard_text = clipboard_text.split('\n') + multi_cursor_paste = len(split_clipboard_text) == len(sel) and len(sel) > 1 + original_selection = list(sel) + regions_to_format = [] # type: List[sublime.Region] + # add regions to selection, in order for lsp_format_document_range to format those regions + for index, region in enumerate(sel): + look_text = clipboard_text + if multi_cursor_paste: + look_text = split_clipboard_text[index] + found_region = self.view.find(look_text, region.end(), sublime.REVERSE | sublime.LITERAL) + if found_region: + regions_to_format.append(found_region) + sel.add_all(regions_to_format) + self.view.run_command('lsp_format_document_range') + sel.clear() + sel.add_all(original_selection) + def _clear_session_views_async(self) -> None: session_views = self._session_views diff --git a/sublime-package.json b/sublime-package.json index 74689be68..ef3b959bb 100644 --- a/sublime-package.json +++ b/sublime-package.json @@ -444,6 +444,11 @@ "default": false, "markdownDescription": "Show errors and warnings count in the status bar." }, + "format_on_paste": { + "type": "boolean", + "default": false, + "markdownDescription": "Run the server's documentRangeFormattingProvider (if supported) on the pasted text." + }, "lsp_format_on_save": { "$ref": "sublime://settings/LSP#/definitions/lsp_format_on_save" }, From 07f23a2af10eb3453dd5bf91db721158b163ad4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Mon, 22 Jan 2024 22:30:30 +0100 Subject: [PATCH 02/19] include whitespace to improve format on paste Including whitespace does help some servers to format a range as expected like LSP-json, See: https://github.com/sublimelsp/LSP/pull/2311#issuecomment-1688593038 --- plugin/documents.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index f5e3cf913..c45cc6345 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -973,14 +973,19 @@ def _format_on_paste_async(self) -> None: multi_cursor_paste = len(split_clipboard_text) == len(sel) and len(sel) > 1 original_selection = list(sel) regions_to_format = [] # type: List[sublime.Region] + pasted_text = clipboard_text # add regions to selection, in order for lsp_format_document_range to format those regions for index, region in enumerate(sel): - look_text = clipboard_text if multi_cursor_paste: - look_text = split_clipboard_text[index] - found_region = self.view.find(look_text, region.end(), sublime.REVERSE | sublime.LITERAL) - if found_region: - regions_to_format.append(found_region) + pasted_text = split_clipboard_text[index] + pasted_region = self.view.find(pasted_text, region.end(), sublime.REVERSE | sublime.LITERAL) + if pasted_region: + # Expand to preceding whitespace on the same line + # More info at https://github.com/sublimelsp/LSP/pull/2311#issuecomment-1688593038 + a = self.view.find_by_class(pasted_region.a, False, + sublime.CLASS_WORD_END | sublime.CLASS_PUNCTUATION_END) + formatting_region = sublime.Region(a, pasted_region.b) + regions_to_format.append(formatting_region) sel.add_all(regions_to_format) self.view.run_command('lsp_format_document_range') sel.clear() From 54c1b64191bb534dd936f2320e266d45fa529fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Mon, 22 Jan 2024 22:32:25 +0100 Subject: [PATCH 03/19] tweak comment --- plugin/documents.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/documents.py b/plugin/documents.py index c45cc6345..8fb03f4d0 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -980,7 +980,7 @@ def _format_on_paste_async(self) -> None: pasted_text = split_clipboard_text[index] pasted_region = self.view.find(pasted_text, region.end(), sublime.REVERSE | sublime.LITERAL) if pasted_region: - # Expand to preceding whitespace on the same line + # Including whitespace may help servers format a range better # More info at https://github.com/sublimelsp/LSP/pull/2311#issuecomment-1688593038 a = self.view.find_by_class(pasted_region.a, False, sublime.CLASS_WORD_END | sublime.CLASS_PUNCTUATION_END) From 0c6068b46c607f96de7a015ec672fb7197ccb186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Mon, 22 Jan 2024 22:33:30 +0100 Subject: [PATCH 04/19] fix flake --- plugin/documents.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/documents.py b/plugin/documents.py index 8fb03f4d0..46a884b2f 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -983,7 +983,7 @@ def _format_on_paste_async(self) -> None: # Including whitespace may help servers format a range better # More info at https://github.com/sublimelsp/LSP/pull/2311#issuecomment-1688593038 a = self.view.find_by_class(pasted_region.a, False, - sublime.CLASS_WORD_END | sublime.CLASS_PUNCTUATION_END) + sublime.CLASS_WORD_END | sublime.CLASS_PUNCTUATION_END) formatting_region = sublime.Region(a, pasted_region.b) regions_to_format.append(formatting_region) sel.add_all(regions_to_format) From 0db49fea1c7a96ad011af6b6c78480722d9cee3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Wed, 24 Jan 2024 21:52:05 +0100 Subject: [PATCH 05/19] move before run_command --- plugin/documents.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/documents.py b/plugin/documents.py index 46a884b2f..9296ba857 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -966,7 +966,6 @@ def _update_stored_selection_async(self) -> Tuple[Optional[sublime.Region], bool return changed_first_region, True def _format_on_paste_async(self) -> None: - self.purge_changes_async() clipboard_text = sublime.get_clipboard() sel = self.view.sel() split_clipboard_text = clipboard_text.split('\n') @@ -987,6 +986,7 @@ def _format_on_paste_async(self) -> None: formatting_region = sublime.Region(a, pasted_region.b) regions_to_format.append(formatting_region) sel.add_all(regions_to_format) + self.purge_changes_async() self.view.run_command('lsp_format_document_range') sel.clear() sel.add_all(original_selection) From 3a2190c2c03c5d1d622c308384e676b92002ab28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Wed, 24 Jan 2024 21:55:45 +0100 Subject: [PATCH 06/19] move up to be before the early return --- plugin/documents.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index 9296ba857..bb7507ec3 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -929,6 +929,9 @@ def _register_async(self) -> None: listener.on_load_async() def _on_view_updated_async(self) -> None: + if self._did_paste: + self._did_paste = False + 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() @@ -939,9 +942,6 @@ def _on_view_updated_async(self) -> None: self._when_selection_remains_stable_async( self._do_highlights_async, first_region, after_ms=self.highlights_debounce_time) self.do_signature_help_async(manual=False) - if self._did_paste: - self._did_paste = False - self._format_on_paste_async() def _update_stored_selection_async(self) -> Tuple[Optional[sublime.Region], bool]: """ From 017eac7a34e9c3ea7b6c424c43b6c22bb46e5a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Wed, 24 Jan 2024 22:13:35 +0100 Subject: [PATCH 07/19] introduce lsp_format_on_paste instead of format_on_paste So it can be defined in Preferences.sublime-settings --- LSP.sublime-settings | 2 +- docs/src/client_configuration.md | 2 +- plugin/core/types.py | 4 ++-- plugin/documents.py | 4 +++- sublime-package.json | 10 +++++++++- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/LSP.sublime-settings b/LSP.sublime-settings index ace2d1301..20d21aa2f 100644 --- a/LSP.sublime-settings +++ b/LSP.sublime-settings @@ -8,7 +8,7 @@ // --- Document Formatting ------------------------------------------------------------ // Run the server's documentRangeFormattingProvider (if supported) on the pasted text. - "format_on_paste": false, + "lsp_format_on_paste": false, // Run the server's formatProvider (if supported) on a file before saving. // This option is also supported in syntax-specific settings and/or in the diff --git a/docs/src/client_configuration.md b/docs/src/client_configuration.md index c75c5ce9a..e56fe8ee7 100644 --- a/docs/src/client_configuration.md +++ b/docs/src/client_configuration.md @@ -79,7 +79,7 @@ The port number can be inserted into the server's startup `command` in your clie ## Per-project overrides -Global LSP settings (which currently are `lsp_format_on_save` and `lsp_code_actions_on_save`) can be overridden per-project in `.sublime-project` file: +Global LSP settings (which currently are `lsp_format_on_save`, `lsp_format_on_paste` and `lsp_code_actions_on_save`) can be overridden per-project in `.sublime-project` file: ```jsonc { diff --git a/plugin/core/types.py b/plugin/core/types.py index 4709a7253..91b7d16df 100644 --- a/plugin/core/types.py +++ b/plugin/core/types.py @@ -205,7 +205,6 @@ class Settings: diagnostics_panel_include_severity_level = cast(int, None) disabled_capabilities = cast(List[str], None) document_highlight_style = cast(str, None) - format_on_paste = cast(bool, None) hover_highlight_style = cast(str, None) inhibit_snippet_completions = cast(bool, None) inhibit_word_completions = cast(bool, None) @@ -216,6 +215,7 @@ class Settings: log_max_size = cast(int, None) log_server = cast(List[str], None) lsp_code_actions_on_save = cast(Dict[str, bool], None) + lsp_format_on_paste = cast(bool, None) lsp_format_on_save = cast(bool, None) on_save_task_timeout_ms = cast(int, None) only_show_lsp_completions = cast(bool, None) @@ -251,13 +251,13 @@ def r(name: str, default: Union[bool, int, str, list, dict]) -> None: r("diagnostics_panel_include_severity_level", 4) r("disabled_capabilities", []) r("document_highlight_style", "underline") - r("format_on_paste", False) r("hover_highlight_style", "") r("initially_folded", []) r("link_highlight_style", "underline") r("log_debug", False) r("log_max_size", 8 * 1024) r("lsp_code_actions_on_save", {}) + r("lsp_format_on_paste", False) r("lsp_format_on_save", False) r("on_save_task_timeout_ms", 2000) r("only_show_lsp_completions", False) diff --git a/plugin/documents.py b/plugin/documents.py index bb7507ec3..0f211f7c0 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -529,7 +529,9 @@ def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[T return None def on_post_text_command(self, command_name: str, args: Optional[Dict[str, Any]]) -> None: - if command_name == 'paste' and userprefs().format_on_paste: + lsp_format_on_paste = self.view.settings().get('lsp_format_on_paste', None) + lsp_format_on_paste_enabled = lsp_format_on_paste if isinstance(lsp_format_on_paste, bool) else userprefs().lsp_format_on_paste + if command_name == 'paste' and lsp_format_on_paste_enabled: self._did_paste = True elif command_name in ("next_field", "prev_field") and args is None: sublime.set_timeout_async(lambda: self.do_signature_help_async(manual=True)) diff --git a/sublime-package.json b/sublime-package.json index ef3b959bb..9b350f057 100644 --- a/sublime-package.json +++ b/sublime-package.json @@ -6,6 +6,11 @@ "$id": "sublime://settings/LSP", "definitions": { // User preferences that are shared with "Preferences.sublime-settings" + "lsp_format_on_paste": { + "type": "boolean", + "default": false, + "markdownDescription": "Run the server's documentRangeFormattingProvider (if supported) on the pasted text." + }, "lsp_format_on_save": { "type": "boolean", "default": false, @@ -444,7 +449,7 @@ "default": false, "markdownDescription": "Show errors and warnings count in the status bar." }, - "format_on_paste": { + "lsp_format_on_paste": { "type": "boolean", "default": false, "markdownDescription": "Run the server's documentRangeFormattingProvider (if supported) on the pasted text." @@ -801,6 +806,9 @@ ], "schema": { "properties": { + "lsp_format_on_paste": { + "$ref": "sublime://settings/LSP#/definitions/lsp_format_on_paste", + }, "lsp_format_on_save": { "$ref": "sublime://settings/LSP#/definitions/lsp_format_on_save", }, From 08f53ea7a7ce12886dfad6eabc51a29946a1220c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Wed, 24 Jan 2024 22:33:36 +0100 Subject: [PATCH 08/19] fix flake --- plugin/documents.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index 0f211f7c0..f6d8f252d 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -529,9 +529,10 @@ def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[T return None def on_post_text_command(self, command_name: str, args: Optional[Dict[str, Any]]) -> None: - lsp_format_on_paste = self.view.settings().get('lsp_format_on_paste', None) - lsp_format_on_paste_enabled = lsp_format_on_paste if isinstance(lsp_format_on_paste, bool) else userprefs().lsp_format_on_paste - if command_name == 'paste' and lsp_format_on_paste_enabled: + format_on_paste = self.view.settings().get('lsp_format_on_paste', None) + format_on_paste_enabled = format_on_paste if isinstance(format_on_paste, bool) \ + else userprefs().lsp_format_on_paste + if command_name == 'paste' and format_on_paste_enabled: self._did_paste = True elif command_name in ("next_field", "prev_field") and args is None: sublime.set_timeout_async(lambda: self.do_signature_help_async(manual=True)) From fdfdbafa701c80802b33018bef2b0734bf3f3e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Wed, 24 Jan 2024 22:34:39 +0100 Subject: [PATCH 09/19] fix over indent flake :( --- plugin/documents.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/documents.py b/plugin/documents.py index f6d8f252d..fef1b4c6b 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -531,7 +531,7 @@ def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[T def on_post_text_command(self, command_name: str, args: Optional[Dict[str, Any]]) -> None: format_on_paste = self.view.settings().get('lsp_format_on_paste', None) format_on_paste_enabled = format_on_paste if isinstance(format_on_paste, bool) \ - else userprefs().lsp_format_on_paste + else userprefs().lsp_format_on_paste if command_name == 'paste' and format_on_paste_enabled: self._did_paste = True elif command_name in ("next_field", "prev_field") and args is None: From 8bf068532933a1dbd8b6c06b0b1f11c8683eb7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Thu, 25 Jan 2024 22:16:57 +0100 Subject: [PATCH 10/19] use $ref for lsp_format_on_paste --- sublime-package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sublime-package.json b/sublime-package.json index 9b350f057..62bb2434b 100644 --- a/sublime-package.json +++ b/sublime-package.json @@ -450,9 +450,7 @@ "markdownDescription": "Show errors and warnings count in the status bar." }, "lsp_format_on_paste": { - "type": "boolean", - "default": false, - "markdownDescription": "Run the server's documentRangeFormattingProvider (if supported) on the pasted text." + "$ref": "sublime://settings/LSP#/definitions/lsp_format_on_paste" }, "lsp_format_on_save": { "$ref": "sublime://settings/LSP#/definitions/lsp_format_on_save" From c9fe44fae50c3a10bd6b9f942c4722e13ce92a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Thu, 25 Jan 2024 22:20:39 +0100 Subject: [PATCH 11/19] Rafal having good suggestions as always :) --- plugin/documents.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index fef1b4c6b..72ce043f3 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -529,10 +529,8 @@ def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[T return None def on_post_text_command(self, command_name: str, args: Optional[Dict[str, Any]]) -> None: - format_on_paste = self.view.settings().get('lsp_format_on_paste', None) - format_on_paste_enabled = format_on_paste if isinstance(format_on_paste, bool) \ - else userprefs().lsp_format_on_paste - if command_name == 'paste' and format_on_paste_enabled: + format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste) + if command_name == 'paste' and format_on_paste: self._did_paste = True elif command_name in ("next_field", "prev_field") and args is None: sublime.set_timeout_async(lambda: self.do_signature_help_async(manual=True)) From c9d1b852b55e41a166c73251da2e9a8be09842f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Thu, 25 Jan 2024 22:35:18 +0100 Subject: [PATCH 12/19] handle paste_and_indent as well if lsp_format_on_paste is enabled --- plugin/documents.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugin/documents.py b/plugin/documents.py index 72ce043f3..16ddfb181 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -520,12 +520,18 @@ def _on_hover_gutter_async(self, point: int) -> None: on_navigate=lambda href: self._on_navigate(href, point)) def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[Tuple[str, dict]]: + format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste) if command_name == "auto_complete": self._auto_complete_triggered_manually = True elif command_name == "show_scope_name" and userprefs().semantic_highlighting: session = self.session_async("semanticTokensProvider") if session: return ("lsp_show_scope_name", {}) + elif command_name == 'paste_and_indent' and format_on_paste: + # if `lsp_format_on_paste` is enabled and paste_and_indent is run, + # it is easier to find the region to format when `paste` is invoked, + # so we intercept the `paste_and_indent` and replace it with the `paste` command. + return ('paste', {}) return None def on_post_text_command(self, command_name: str, args: Optional[Dict[str, Any]]) -> None: From f654bc813a0aa7b222efe461934759e3ca794a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Thu, 25 Jan 2024 23:43:01 +0100 Subject: [PATCH 13/19] make sure that we have LSP running before we override the paste_and_indent and generally make sure to run format_on_paste if the session supports documentRangeFormattingProvider --- plugin/documents.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index 16ddfb181..5ef095eee 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -170,7 +170,7 @@ def on_change() -> None: self._registration = SettingsRegistration(view.settings(), on_change=on_change) self._completions_task = None # type: Optional[QueryCompletionsTask] self._stored_selection = [] # type: List[sublime.Region] - self._did_paste = False + self._should_format_on_paste = False self._setup() def __del__(self) -> None: @@ -531,13 +531,15 @@ def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[T # if `lsp_format_on_paste` is enabled and paste_and_indent is run, # it is easier to find the region to format when `paste` is invoked, # so we intercept the `paste_and_indent` and replace it with the `paste` command. - return ('paste', {}) + if self.session_async("documentRangeFormattingProvider"): + return ('paste', {}) return None def on_post_text_command(self, command_name: str, args: Optional[Dict[str, Any]]) -> None: format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste) if command_name == 'paste' and format_on_paste: - self._did_paste = True + if self.session_async("documentRangeFormattingProvider"): + self._should_format_on_paste = True elif command_name in ("next_field", "prev_field") and args is None: sublime.set_timeout_async(lambda: self.do_signature_help_async(manual=True)) if not self.view.is_popup_visible(): @@ -936,8 +938,8 @@ def _register_async(self) -> None: listener.on_load_async() def _on_view_updated_async(self) -> None: - if self._did_paste: - self._did_paste = False + if self._should_format_on_paste: + self._should_format_on_paste = False self._format_on_paste_async() self._code_lenses_debouncer_async.debounce( self._do_code_lenses_async, timeout_ms=self.code_lenses_debounce_time) From 4346bae165ff532ac5b288c9ed61fac05822ffa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Mon, 29 Jan 2024 21:49:48 +0100 Subject: [PATCH 14/19] Update plugin/documents.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rafał Chłodnicki --- plugin/documents.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index 5ef095eee..218ea19f4 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -527,11 +527,12 @@ def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[T session = self.session_async("semanticTokensProvider") if session: return ("lsp_show_scope_name", {}) - elif command_name == 'paste_and_indent' and format_on_paste: + elif command_name == 'paste_and_indent' # if `lsp_format_on_paste` is enabled and paste_and_indent is run, # it is easier to find the region to format when `paste` is invoked, # so we intercept the `paste_and_indent` and replace it with the `paste` command. - if self.session_async("documentRangeFormattingProvider"): + format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste): + if format_on_paste and self.session_async("documentRangeFormattingProvider"): return ('paste', {}) return None From 774621557e5df292ac84db9306a319b9bdaae992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Mon, 29 Jan 2024 21:51:36 +0100 Subject: [PATCH 15/19] fix : --- plugin/documents.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index 218ea19f4..1803249de 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -527,11 +527,11 @@ def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[T session = self.session_async("semanticTokensProvider") if session: return ("lsp_show_scope_name", {}) - elif command_name == 'paste_and_indent' + elif command_name == 'paste_and_indent': # if `lsp_format_on_paste` is enabled and paste_and_indent is run, # it is easier to find the region to format when `paste` is invoked, # so we intercept the `paste_and_indent` and replace it with the `paste` command. - format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste): + format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste) if format_on_paste and self.session_async("documentRangeFormattingProvider"): return ('paste', {}) return None From 3d52e7a147a13455da0144b546e0a092fa29caed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Mon, 29 Jan 2024 21:52:10 +0100 Subject: [PATCH 16/19] the first paragraph is not necessary --- plugin/documents.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/documents.py b/plugin/documents.py index 1803249de..b9f8a6d00 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -528,7 +528,6 @@ def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[T if session: return ("lsp_show_scope_name", {}) elif command_name == 'paste_and_indent': - # if `lsp_format_on_paste` is enabled and paste_and_indent is run, # it is easier to find the region to format when `paste` is invoked, # so we intercept the `paste_and_indent` and replace it with the `paste` command. format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste) From 861d047312525cbeafd1d2d5574b43e785a38e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Mon, 29 Jan 2024 23:04:56 +0100 Subject: [PATCH 17/19] remove unnecessary line and move inside if --- plugin/documents.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index b9f8a6d00..eea8856ea 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -520,7 +520,6 @@ def _on_hover_gutter_async(self, point: int) -> None: on_navigate=lambda href: self._on_navigate(href, point)) def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[Tuple[str, dict]]: - format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste) if command_name == "auto_complete": self._auto_complete_triggered_manually = True elif command_name == "show_scope_name" and userprefs().semantic_highlighting: @@ -536,9 +535,9 @@ def on_text_command(self, command_name: str, args: Optional[dict]) -> Optional[T return None def on_post_text_command(self, command_name: str, args: Optional[Dict[str, Any]]) -> None: - format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste) - if command_name == 'paste' and format_on_paste: - if self.session_async("documentRangeFormattingProvider"): + if command_name == 'paste': + format_on_paste = self.view.settings().get('lsp_format_on_paste', userprefs().lsp_format_on_paste) + if format_on_paste and self.session_async("documentRangeFormattingProvider"): self._should_format_on_paste = True elif command_name in ("next_field", "prev_field") and args is None: sublime.set_timeout_async(lambda: self.do_signature_help_async(manual=True)) From 0cfcc71b41e9bd4e898a0ff8e9b864d9a97399f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Thu, 1 Feb 2024 12:32:14 +0100 Subject: [PATCH 18/19] avoid quick flash of selected region before format is run Before, occasionally it was possible to see a brief moment when text gets selected, Now, we move that from the async thread to the main thread, thus we will not see that flash --- plugin/documents.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugin/documents.py b/plugin/documents.py index eea8856ea..71e97be1e 100644 --- a/plugin/documents.py +++ b/plugin/documents.py @@ -993,11 +993,15 @@ def _format_on_paste_async(self) -> None: sublime.CLASS_WORD_END | sublime.CLASS_PUNCTUATION_END) formatting_region = sublime.Region(a, pasted_region.b) regions_to_format.append(formatting_region) - sel.add_all(regions_to_format) self.purge_changes_async() - self.view.run_command('lsp_format_document_range') - sel.clear() - sel.add_all(original_selection) + + def run_sync() -> None: + sel.add_all(regions_to_format) + self.view.run_command('lsp_format_document_range') + sel.clear() + sel.add_all(original_selection) + + sublime.set_timeout(run_sync) def _clear_session_views_async(self) -> None: session_views = self._session_views From 1a50fb989f5975e22afd2dc41b81550670b5516e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=80=D0=B5=D0=B4=D1=80=D0=B0=D0=B3=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BB=D0=B8=D1=9B?= Date: Thu, 1 Feb 2024 23:26:03 +0100 Subject: [PATCH 19/19] update text to be more user friendly --- LSP.sublime-settings | 4 ++-- sublime-package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LSP.sublime-settings b/LSP.sublime-settings index 20d21aa2f..4a84fd54f 100644 --- a/LSP.sublime-settings +++ b/LSP.sublime-settings @@ -7,10 +7,10 @@ // --- Document Formatting ------------------------------------------------------------ - // Run the server's documentRangeFormattingProvider (if supported) on the pasted text. + // If supported, format the pasted text. "lsp_format_on_paste": false, - // Run the server's formatProvider (if supported) on a file before saving. + // If supported, format a file before saving. // This option is also supported in syntax-specific settings and/or in the // "settings" section of project files. "lsp_format_on_save": false, diff --git a/sublime-package.json b/sublime-package.json index 62bb2434b..632870d7f 100644 --- a/sublime-package.json +++ b/sublime-package.json @@ -9,12 +9,12 @@ "lsp_format_on_paste": { "type": "boolean", "default": false, - "markdownDescription": "Run the server's documentRangeFormattingProvider (if supported) on the pasted text." + "markdownDescription": "If supported, format the pasted text." }, "lsp_format_on_save": { "type": "boolean", "default": false, - "markdownDescription": "Run the server's formatProvider (if supported) on a document before saving. This option is also supported in syntax-specific settings and/or in the `\"settings\"` section of project files." + "markdownDescription": "If supported, format a file before saving. This option is also supported in syntax-specific settings and/or in the `\"settings\"` section of project files." }, "lsp_code_actions_on_save": { "type": "object",