From 7da5311f6d8d68f66dc20db989583e8e0e59b574 Mon Sep 17 00:00:00 2001 From: Naoki Ikeguchi Date: Wed, 14 May 2025 15:58:25 +0900 Subject: [PATCH 1/2] fix(lsp): compare only the formatted range on range formatting --- crates/biome_lsp/src/handlers/formatting.rs | 24 +++++--- crates/biome_lsp/src/server.tests.rs | 66 +++++++++++++++++++++ 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/crates/biome_lsp/src/handlers/formatting.rs b/crates/biome_lsp/src/handlers/formatting.rs index 876fb812ce0e..6ca4384e9590 100644 --- a/crates/biome_lsp/src/handlers/formatting.rs +++ b/crates/biome_lsp/src/handlers/formatting.rs @@ -4,7 +4,7 @@ use crate::utils::text_edit; use anyhow::Context; use biome_fs::BiomePath; use biome_lsp_converters::from_proto; -use biome_rowan::{TextRange, TextSize}; +use biome_rowan::{TextLen, TextRange, TextSize}; use biome_service::file_handlers::{AstroFileHandler, SvelteFileHandler, VueFileHandler}; use biome_service::workspace::{ CheckFileSizeParams, FeaturesBuilder, FileFeaturesResult, FormatFileParams, FormatOnTypeParams, @@ -149,14 +149,19 @@ pub(crate) fn format_range( range: format_range, })?; - let indels = - biome_text_edit::TextEdit::from_unicode_words(content.as_str(), formatted.as_code()); + let formatted_range = formatted + .range() + .unwrap_or_else(|| TextRange::up_to(content.text_len())); + let indels = biome_text_edit::TextEdit::from_unicode_words( + &content.as_str()[formatted_range], + formatted.as_code(), + ); let position_encoding = session.position_encoding(); let edits = text_edit( &doc.line_index, indels, position_encoding, - Some(format_range.start().into()), + Some(formatted_range.start().into()), )?; Ok(Some(edits)) @@ -217,13 +222,18 @@ pub(crate) fn format_on_type( path: path.clone(), })?; - let indels = - biome_text_edit::TextEdit::from_unicode_words(content.as_str(), formatted.as_code()); + let formatted_range = formatted + .range() + .unwrap_or_else(|| TextRange::up_to(content.text_len())); + let indels = biome_text_edit::TextEdit::from_unicode_words( + &content.as_str()[formatted_range], + formatted.as_code(), + ); let edits = text_edit( &doc.line_index, indels, position_encoding, - Some(offset.into()), + Some(formatted_range.start().into()), )?; Ok(Some(edits)) } else { diff --git a/crates/biome_lsp/src/server.tests.rs b/crates/biome_lsp/src/server.tests.rs index cbe59007555c..7a8c3d8922c8 100644 --- a/crates/biome_lsp/src/server.tests.rs +++ b/crates/biome_lsp/src/server.tests.rs @@ -793,6 +793,72 @@ async fn document_no_extension() -> Result<()> { Ok(()) } +#[tokio::test] +async fn document_range_formatting() -> Result<()> { + let factory = ServerFactory::default(); + let (service, client) = factory.create().into_inner(); + let (stream, sink) = client.split(); + let mut server = Server::new(service); + + let (sender, _) = channel(CHANNEL_BUFFER_SIZE); + let reader = tokio::spawn(client_handler(stream, sink, sender)); + + server.initialize().await?; + server.initialized().await?; + + server + .notify( + "textDocument/didOpen", + DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: uri!("document.js"), + language_id: String::from("javascript"), + version: 0, + text: String::from("doNotFormatHere()\nformatHere()\ndoNotFormatHere()\n"), + }, + }, + ) + .await?; + + let res: Option> = server + .request( + "textDocument/rangeFormatting", + "formatting", + DocumentRangeFormattingParams { + text_document: TextDocumentIdentifier { + uri: uri!("document.js"), + }, + range: Range::new(Position::new(1, 0), Position::new(2, 0)), + options: FormattingOptions { + tab_size: 4, + insert_spaces: false, + properties: HashMap::default(), + trim_trailing_whitespace: None, + insert_final_newline: None, + trim_final_newlines: None, + }, + work_done_progress_params: WorkDoneProgressParams { + work_done_token: None, + }, + }, + ) + .await? + .context("formatting returned None")?; + + assert_eq!( + res.context("formatting did not return an edit list")?, + vec![TextEdit::new( + Range::new(Position::new(1, 12), Position::new(1, 12)), + ";".to_string() + )] + ); + + server.shutdown().await?; + reader.abort(); + + Ok(()) +} + #[tokio::test] async fn pull_diagnostics() -> Result<()> { let factory = ServerFactory::default(); From 400d462e8aef2a26fa5d73c5110878972cf3d160 Mon Sep 17 00:00:00 2001 From: Naoki Ikeguchi Date: Wed, 14 May 2025 17:05:26 +0900 Subject: [PATCH 2/2] chore: add changeset --- .changeset/eleven-feet-heal.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/eleven-feet-heal.md diff --git a/.changeset/eleven-feet-heal.md b/.changeset/eleven-feet-heal.md new file mode 100644 index 000000000000..5f50d8dd7ed9 --- /dev/null +++ b/.changeset/eleven-feet-heal.md @@ -0,0 +1,5 @@ +--- +"@biomejs/biome": patch +--- + +Fixed [#2260](https://github.com/biomejs/biome/2260): The LSP server now returns correct text edits for the specified range in `textDocument/rangeFormatting` and `textDocument/onTypeFormatting` requests.