diff --git a/Default.sublime-keymap b/Default.sublime-keymap index bd59e5a76..325077470 100644 --- a/Default.sublime-keymap +++ b/Default.sublime-keymap @@ -247,6 +247,7 @@ { "keys": ["primary+s"], "command": "lsp_save", + "args": {"async": true}, "context": [{"key": "lsp.session_with_capability", "operand": "textDocumentSync.willSave | textDocumentSync.willSaveWaitUntil | codeActionProvider.codeActionKinds | documentFormattingProvider | documentRangeFormattingProvider"}] }, ] diff --git a/plugin/save_command.py b/plugin/save_command.py index eb35f654b..03c8687d1 100644 --- a/plugin/save_command.py +++ b/plugin/save_command.py @@ -1,6 +1,6 @@ from .core.registry import LspTextCommand from .core.settings import userprefs -from .core.typing import Callable, List, Type +from .core.typing import Any, Callable, Dict, List, Type from abc import ABCMeta, abstractmethod import sublime import sublime_plugin @@ -75,12 +75,14 @@ def register_task(cls, task: Type[SaveTask]) -> None: def __init__(self, view: sublime.View) -> None: super().__init__(view) self._pending_tasks = [] # type: List[SaveTask] + self._kwargs = {} # type: Dict[str, Any] - def run(self, edit: sublime.Edit) -> None: + def run(self, edit: sublime.Edit, **kwargs: Dict[str, Any]) -> None: if self._pending_tasks: for task in self._pending_tasks: task.cancel() self._pending_tasks = [] + self._kwargs = kwargs sublime.set_timeout_async(self._trigger_on_pre_save_async) for Task in self._tasks: if Task.is_applicable(self.view): @@ -113,7 +115,7 @@ def _on_task_completed_async(self) -> None: def _trigger_native_save(self) -> None: # Triggered from set_timeout to preserve original semantics of on_pre_save handling - sublime.set_timeout(lambda: self.view.run_command('save', {"async": True})) + sublime.set_timeout(lambda: self.view.run_command('save', self._kwargs)) class LspSaveAllCommand(sublime_plugin.WindowCommand): @@ -128,4 +130,4 @@ def run(self, only_files: bool = False) -> None: if only_files and view.file_name() is None: continue done.add(buffer_id) - view.run_command("lsp_save", None) + view.run_command("lsp_save", {'async': True}) diff --git a/tests/test_code_actions.py b/tests/test_code_actions.py index 3841e8352..e4231917e 100644 --- a/tests/test_code_actions.py +++ b/tests/test_code_actions.py @@ -118,7 +118,7 @@ def test_applies_matching_kind(self) -> Generator: code_action_kind ) self.set_response('textDocument/codeAction', [code_action]) - self.view.run_command('lsp_save') + self.view.run_command('lsp_save', {'async': True}) yield from self.await_message('textDocument/codeAction') yield from self.await_message('textDocument/didSave') self.assertEquals(entire_content(self.view), 'const x = 1;') @@ -134,7 +134,7 @@ def test_requests_with_diagnostics(self) -> Generator: code_action_kind ) self.set_response('textDocument/codeAction', [code_action]) - self.view.run_command('lsp_save') + self.view.run_command('lsp_save', {'async': True}) code_action_request = yield from self.await_message('textDocument/codeAction') self.assertEquals(len(code_action_request['context']['diagnostics']), 1) self.assertEquals(code_action_request['context']['diagnostics'][0]['message'], 'Missing semicolon') @@ -176,7 +176,7 @@ def test_applies_only_one_pass(self) -> Generator: ] ), ]) - self.view.run_command('lsp_save') + self.view.run_command('lsp_save', {'async': True}) # Wait for the view to be saved yield lambda: not self.view.is_dirty() self.assertEquals(entire_content(self.view), 'const x = 1;') @@ -191,7 +191,7 @@ def test_applies_immediately_after_text_change(self) -> Generator: code_action_kind ) self.set_response('textDocument/codeAction', [code_action]) - self.view.run_command('lsp_save') + self.view.run_command('lsp_save', {'async': True}) yield from self.await_message('textDocument/codeAction') yield from self.await_message('textDocument/didSave') self.assertEquals(entire_content(self.view), 'const x = 1;') @@ -200,7 +200,7 @@ def test_applies_immediately_after_text_change(self) -> Generator: def test_no_fix_on_non_matching_kind(self) -> Generator: yield from self._setup_document_with_missing_semicolon() initial_content = 'const x = 1' - self.view.run_command('lsp_save') + self.view.run_command('lsp_save', {'async': True}) yield from self.await_message('textDocument/didSave') self.assertEquals(entire_content(self.view), initial_content) self.assertEquals(self.view.is_dirty(), False) @@ -215,7 +215,7 @@ def test_does_not_apply_unsupported_kind(self) -> Generator: code_action_kind ) self.set_response('textDocument/codeAction', [code_action]) - self.view.run_command('lsp_save') + self.view.run_command('lsp_save', {'async': True}) yield from self.await_message('textDocument/didSave') self.assertEquals(entire_content(self.view), 'const x = 1') diff --git a/tests/test_single_document.py b/tests/test_single_document.py index 50a45a06f..74c3f7f78 100644 --- a/tests/test_single_document.py +++ b/tests/test_single_document.py @@ -106,7 +106,7 @@ def test_sends_save_with_purge(self) -> 'Generator': assert self.view self.view.settings().set("lsp_format_on_save", False) self.insert_characters("A") - self.view.run_command("lsp_save") + self.view.run_command("lsp_save", {'async': True}) yield from self.await_message("textDocument/didChange") yield from self.await_message("textDocument/didSave") yield from self.await_clear_view_and_save() @@ -123,7 +123,7 @@ def test_formats_on_save(self) -> 'Generator': 'end': {'line': 0, 'character': 1} } }]) - self.view.run_command("lsp_save") + self.view.run_command("lsp_save", {'async': True}) yield from self.await_message("textDocument/formatting") yield from self.await_message("textDocument/didChange") yield from self.await_message("textDocument/didSave") @@ -384,7 +384,7 @@ def test_will_save_wait_until(self) -> 'Generator': } }]) self.view.settings().set("lsp_format_on_save", False) - self.view.run_command("lsp_save") + self.view.run_command("lsp_save", {'async': True}) yield from self.await_message("textDocument/willSaveWaitUntil") yield from self.await_message("textDocument/didChange") yield from self.await_message("textDocument/didSave")