From f85186fa5e7bd7a060884681eaf4d86501f4e681 Mon Sep 17 00:00:00 2001 From: Rolo Date: Sun, 21 Jul 2024 13:52:07 -0700 Subject: [PATCH] fix(lsp): add fallback for range completion edits Fix off-by-one error with LSP completion edits beyond document end. Add fallback to handle incorrect ranges and prevent index out of bounds panic. Default to correct range first, retry with `end - 1` if necessary. --- helix-lsp/src/lib.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index ec89e1f821865..be45e29552f86 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -330,14 +330,24 @@ pub mod util { }; let text = doc.slice(..); - let (removed_start, removed_end) = completion_range( + let (start, end) = completion_range( text, edit_offset, replace_mode, selection.primary().cursor(text), ) .expect("transaction must be valid for primary selection"); - let removed_text = text.slice(removed_start..removed_end); + + // Some LSPs are sending completion edits beyond the end of the document. For example, pyright for python. + // + // In https://github.com/helix-editor/helix/pull/10279, there was the addition of a `+ 1` to fix an off by one + // error, but this has now ran into another for some LSP's that don't report the proper range, leading to an + // index out of bounds panic. The "solution" here is to default to the "correct" way first and if that too is + // out of bounds, it tries again with the `end - 1`, hopefully bringing it back into the correct range. If even + // that isn't correct, we panic as before. + let removed_text = text + .get_slice(start..end) + .map_or_else(|| text.slice(start..end - 1), |replaced| replaced); let (transaction, mut selection) = Transaction::change_by_selection_ignore_overlapping( doc,