From 45eb0e788986a988392f6044ca80b496225babdf Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 26 Jul 2022 08:43:27 +0200 Subject: [PATCH] Clip invalid edits from LSP instead of reporting an error This fixes an issue with the Go language server, which reports invalid formatting ranges when there's a missing newline at the end of the file. Specifically, if the buffer is `N` lines long, it will try to insert the newline at `Point(N + 1, 0)`. I confirmed the behavior is the same in VS Code, and they indeed clip the LSP ranges as well. --- crates/project/src/project.rs | 10 ++++------ crates/project/src/project_tests.rs | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 759eb90194..e116761eb9 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -5764,6 +5764,10 @@ impl Project { let mut lsp_edits = lsp_edits.into_iter().peekable(); let mut edits = Vec::new(); while let Some((mut range, mut new_text)) = lsp_edits.next() { + // Clip invalid ranges provided by the language server. + range.start = snapshot.clip_point_utf16(range.start, Bias::Left); + range.end = snapshot.clip_point_utf16(range.end, Bias::Left); + // Combine any LSP edits that are adjacent. // // Also, combine LSP edits that are separated from each other by only @@ -5791,12 +5795,6 @@ impl Project { lsp_edits.next(); } - if snapshot.clip_point_utf16(range.start, Bias::Left) != range.start - || snapshot.clip_point_utf16(range.end, Bias::Left) != range.end - { - return Err(anyhow!("invalid edits received from language server")); - } - // For multiline edits, perform a diff of the old and new text so that // we can identify the changes more precisely, preserving the locations // of any anchors positioned in the unchanged regions. diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 1080daff1d..e36bd2c75a 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -1565,7 +1565,7 @@ async fn test_invalid_edits_from_lsp(cx: &mut gpui::TestAppContext) { .unwrap(); // Simulate the language server sending us edits in a non-ordered fashion, - // with ranges sometimes being inverted. + // with ranges sometimes being inverted or pointing to invalid locations. let edits = project .update(cx, |project, cx| { project.edits_from_lsp( @@ -1580,7 +1580,7 @@ async fn test_invalid_edits_from_lsp(cx: &mut gpui::TestAppContext) { new_text: "a::{b, c}".into(), }, lsp::TextEdit { - range: lsp::Range::new(lsp::Position::new(1, 0), lsp::Position::new(7, 0)), + range: lsp::Range::new(lsp::Position::new(1, 0), lsp::Position::new(99, 0)), new_text: "".into(), }, lsp::TextEdit {