From 17fa510e7286962cd75c18fe5af4e6612359b1aa Mon Sep 17 00:00:00 2001 From: Janos Wortmann Date: Fri, 14 Jul 2023 20:02:18 +0200 Subject: [PATCH 1/2] Add support for multi-range formatting --- plugin/core/sessions.py | 3 ++- plugin/core/views.py | 8 ++++++++ plugin/formatting.py | 39 ++++++++++++++++++++++++++++++--------- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/plugin/core/sessions.py b/plugin/core/sessions.py index 42c57e5b6..9b43b5a80 100644 --- a/plugin/core/sessions.py +++ b/plugin/core/sessions.py @@ -331,7 +331,8 @@ def get_initialize_params(variables: Dict[str, str], workspace_folders: List[Wor "tooltipSupport": True }, "formatting": { - "dynamicRegistration": True # exceptional + "dynamicRegistration": True, # exceptional + "rangesSupport": True # pyright: ignore # remove this comment after LSP types are updated }, "rangeFormatting": { "dynamicRegistration": True diff --git a/plugin/core/views.py b/plugin/core/views.py index ba1bcdd31..c2a20cfae 100644 --- a/plugin/core/views.py +++ b/plugin/core/views.py @@ -592,6 +592,14 @@ def text_document_range_formatting(view: sublime.View, region: sublime.Region) - }, view, progress=True) +def text_document_ranges_formatting(view: sublime.View) -> Request: + return Request("textDocument/rangesFormatting", { + "textDocument": text_document_identifier(view), + "options": formatting_options(view.settings()), + "ranges": [region_to_range(view, region) for region in view.sel() if not region.empty()] + }, view, progress=True) + + def selection_range_params(view: sublime.View) -> SelectionRangeParams: return { "textDocument": text_document_identifier(view), diff --git a/plugin/formatting.py b/plugin/formatting.py index bd2ba297f..f6247c836 100644 --- a/plugin/formatting.py +++ b/plugin/formatting.py @@ -12,6 +12,7 @@ from .core.views import has_single_nonempty_selection from .core.views import text_document_formatting from .core.views import text_document_range_formatting +from .core.views import text_document_ranges_formatting from .core.views import will_save_wait_until from .save_command import LspSaveCommand, SaveTask import sublime @@ -115,16 +116,27 @@ class LspFormatDocumentRangeCommand(LspTextCommand): capability = 'documentRangeFormattingProvider' def is_enabled(self, event: Optional[dict] = None, point: Optional[int] = None) -> bool: - if super().is_enabled(event, point): - return has_single_nonempty_selection(self.view) + if not super().is_enabled(event, point): + return False + if has_single_nonempty_selection(self.view): + return True + if self.view.has_non_empty_selection_region() and \ + bool(self.best_session('documentRangeFormattingProvider.rangesSupport')): + return True return False def run(self, edit: sublime.Edit, event: Optional[dict] = None) -> None: - session = self.best_session(self.capability) - selection = first_selection_region(self.view) - if session and selection is not None: - req = text_document_range_formatting(self.view, selection) - session.send_request(req, lambda response: apply_text_edits_to_view(response, self.view)) + if has_single_nonempty_selection(self.view): + session = self.best_session(self.capability) + selection = first_selection_region(self.view) + if session and selection is not None: + req = text_document_range_formatting(self.view, selection) + session.send_request(req, lambda response: apply_text_edits_to_view(response, self.view)) + elif self.view.has_non_empty_selection_region(): + session = self.best_session('documentRangeFormattingProvider.rangesSupport') + if session: + req = text_document_ranges_formatting(self.view) + session.send_request(req, lambda response: apply_text_edits_to_view(response, self.view)) class LspFormatCommand(LspTextCommand): @@ -139,11 +151,20 @@ def is_visible(self, event: Optional[dict] = None, point: Optional[int] = None) return self.is_enabled(event, point) def description(self, **kwargs) -> str: - return "Format Selection" if self._range_formatting_available() else "Format File" + if self._range_formatting_available(): + if has_single_nonempty_selection(self.view): + return "Format Selection" + return "Format Selections" + return "Format File" def run(self, edit: sublime.Edit, event: Optional[dict] = None) -> None: command = 'lsp_format_document_range' if self._range_formatting_available() else 'lsp_format_document' self.view.run_command(command) def _range_formatting_available(self) -> bool: - return has_single_nonempty_selection(self.view) and bool(self.best_session('documentRangeFormattingProvider')) + if has_single_nonempty_selection(self.view) and bool(self.best_session('documentRangeFormattingProvider')): + return True + if self.view.has_non_empty_selection_region() and \ + bool(self.best_session('documentRangeFormattingProvider.rangesSupport')): + return True + return False From 59f3cd6100cc606d14a5594d18d6d8b82ef93bfb Mon Sep 17 00:00:00 2001 From: Janos Wortmann Date: Fri, 4 Aug 2023 16:38:01 +0200 Subject: [PATCH 2/2] Bug detected --- plugin/core/sessions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin/core/sessions.py b/plugin/core/sessions.py index 9b43b5a80..02d387e28 100644 --- a/plugin/core/sessions.py +++ b/plugin/core/sessions.py @@ -331,11 +331,11 @@ def get_initialize_params(variables: Dict[str, str], workspace_folders: List[Wor "tooltipSupport": True }, "formatting": { - "dynamicRegistration": True, # exceptional - "rangesSupport": True # pyright: ignore # remove this comment after LSP types are updated + "dynamicRegistration": True # exceptional }, "rangeFormatting": { - "dynamicRegistration": True + "dynamicRegistration": True, + "rangesSupport": True }, "declaration": { "dynamicRegistration": True,