diff --git a/crates/ruff_server/src/format.rs b/crates/ruff_server/src/format.rs index 05708326be234..a2257ccedfc88 100644 --- a/crates/ruff_server/src/format.rs +++ b/crates/ruff_server/src/format.rs @@ -1,6 +1,6 @@ use ruff_formatter::PrintedRange; use ruff_python_ast::PySourceType; -use ruff_python_formatter::format_module_source; +use ruff_python_formatter::{format_module_source, FormatModuleError}; use ruff_text_size::TextRange; use ruff_workspace::FormatterSettings; @@ -10,10 +10,25 @@ pub(crate) fn format( document: &TextDocument, source_type: PySourceType, formatter_settings: &FormatterSettings, -) -> crate::Result { +) -> crate::Result> { let format_options = formatter_settings.to_format_options(source_type, document.contents()); - let formatted = format_module_source(document.contents(), format_options)?; - Ok(formatted.into_code()) + match format_module_source(document.contents(), format_options) { + Ok(formatted) => { + let formatted = formatted.into_code(); + if formatted == document.contents() { + Ok(None) + } else { + Ok(Some(formatted)) + } + } + // Special case - syntax/parse errors are handled here instead of + // being propagated as visible server errors. + Err(FormatModuleError::ParseError(error)) => { + tracing::warn!("Unable to format document: {error}"); + Ok(None) + } + Err(err) => Err(err.into()), + } } pub(crate) fn format_range( @@ -21,12 +36,23 @@ pub(crate) fn format_range( source_type: PySourceType, formatter_settings: &FormatterSettings, range: TextRange, -) -> crate::Result { +) -> crate::Result> { let format_options = formatter_settings.to_format_options(source_type, document.contents()); - Ok(ruff_python_formatter::format_range( - document.contents(), - range, - format_options, - )?) + match ruff_python_formatter::format_range(document.contents(), range, format_options) { + Ok(formatted) => { + if formatted.as_code() == document.contents() { + Ok(None) + } else { + Ok(Some(formatted)) + } + } + // Special case - syntax/parse errors are handled here instead of + // being propagated as visible server errors. + Err(FormatModuleError::ParseError(error)) => { + tracing::warn!("Unable to format document range: {error}"); + Ok(None) + } + Err(err) => Err(err.into()), + } } diff --git a/crates/ruff_server/src/server/api/requests/format.rs b/crates/ruff_server/src/server/api/requests/format.rs index 917b6bf45aa8b..b8d4d27c1f853 100644 --- a/crates/ruff_server/src/server/api/requests/format.rs +++ b/crates/ruff_server/src/server/api/requests/format.rs @@ -98,13 +98,11 @@ fn format_text_document( } let source = text_document.contents(); - let mut formatted = - crate::format::format(text_document, query.source_type(), formatter_settings) - .with_failure_code(lsp_server::ErrorCode::InternalError)?; - // fast path - if the code is the same, return early - if formatted == source { + let formatted = crate::format::format(text_document, query.source_type(), formatter_settings) + .with_failure_code(lsp_server::ErrorCode::InternalError)?; + let Some(mut formatted) = formatted else { return Ok(None); - } + }; // special case - avoid adding a newline to a notebook cell if it didn't already exist if is_notebook { diff --git a/crates/ruff_server/src/server/api/requests/format_range.rs b/crates/ruff_server/src/server/api/requests/format_range.rs index 7b678a3e16c00..54ea1699b8f19 100644 --- a/crates/ruff_server/src/server/api/requests/format_range.rs +++ b/crates/ruff_server/src/server/api/requests/format_range.rs @@ -73,10 +73,12 @@ fn format_text_document_range( ) .with_failure_code(lsp_server::ErrorCode::InternalError)?; - Ok(Some(vec![types::TextEdit { - range: formatted_range - .source_range() - .to_range(text, index, encoding), - new_text: formatted_range.into_code(), - }])) + Ok(formatted_range.map(|formatted_range| { + vec![types::TextEdit { + range: formatted_range + .source_range() + .to_range(text, index, encoding), + new_text: formatted_range.into_code(), + }] + })) }