diff --git a/ruff_lsp/server.py b/ruff_lsp/server.py index 98afef2..e1e6091 100755 --- a/ruff_lsp/server.py +++ b/ruff_lsp/server.py @@ -1095,10 +1095,14 @@ async def apply_organize_imports(arguments: tuple[TextDocument]): async def apply_format(arguments: tuple[TextDocument]): uri = arguments[0]["uri"] document = Document.from_uri(uri) - results = await _run_format_on_document(document) - workspace_edit = _result_to_workspace_edit(document, results) + + result = await _run_format_on_document(document) + if result is None or result.exit_code != 0: + return None + + workspace_edit = _result_to_workspace_edit(document, result) if workspace_edit is None: - return + return None LSP_SERVER.apply_edit(workspace_edit, "Ruff: Format document") @@ -1108,8 +1112,9 @@ async def format_document(params: DocumentFormattingParams) -> list[TextEdit] | # request itself can only act on a text document. A cell in a Notebook is # represented as a text document. document = Document.from_cell_or_text_uri(params.text_document.uri) + result = await _run_format_on_document(document) - if result is None: + if result is None or result.exit_code != 0: return None if document.kind is DocumentKind.Cell: @@ -1330,7 +1335,10 @@ async def run_path( stdin=asyncio.subprocess.PIPE, cwd=cwd, ) - result = RunResult(*await process.communicate(input=source.encode("utf-8"))) + result = RunResult( + *await process.communicate(input=source.encode("utf-8")), + exit_code=await process.wait(), + ) if result.stderr: log_to_output(result.stderr.decode("utf-8")) diff --git a/ruff_lsp/utils.py b/ruff_lsp/utils.py index 30ac039..d7aae5a 100644 --- a/ruff_lsp/utils.py +++ b/ruff_lsp/utils.py @@ -69,6 +69,7 @@ def version(executable: str) -> Version: class RunResult: """Object to hold result from running tool.""" - def __init__(self, stdout: bytes, stderr: bytes): + def __init__(self, stdout: bytes, stderr: bytes, exit_code: int): self.stdout: bytes = stdout self.stderr: bytes = stderr + self.exit_code: int = exit_code diff --git a/tests/test_format.py b/tests/test_format.py index a7f20fb..dd13cbe 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -40,7 +40,33 @@ async def test_format(tmp_path, ruff_version: Version): with handle_unsupported: result = await _run_format_on_document(document) assert result is not None + assert result.exit_code == 0 [edit] = _fixed_source_to_edits( original_source=document.source, fixed_source=result.stdout.decode("utf-8") ) assert edit.new_text == expected + + +@pytest.mark.asyncio +async def test_format_code_with_syntax_error(tmp_path, ruff_version: Version): + source = """ +foo = +""" + + test_file = tmp_path.joinpath("main.py") + test_file.write_text(source) + uri = utils.as_uri(str(test_file)) + + workspace = Workspace(str(tmp_path)) + document = Document.from_text_document(workspace.get_text_document(uri)) + + handle_unsupported = ( + pytest.raises(RuntimeError, match=f"Ruff .* required, but found {ruff_version}") + if not VERSION_REQUIREMENT_FORMATTER.contains(ruff_version) + else nullcontext() + ) + + with handle_unsupported: + result = await _run_format_on_document(document) + assert result is not None + assert result.exit_code == 2