Fix panic in handling edits to combined injections

Max Brunsfeld created

Change summary

crates/language/src/syntax_map.rs | 41 +++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 2 deletions(-)

Detailed changes

crates/language/src/syntax_map.rs 🔗

@@ -1082,15 +1082,34 @@ fn splice_included_ranges(
         }
 
         if let Some(changed) = changed_range {
-            let start_ix = ranges_ix
+            let mut start_ix = ranges_ix
                 + match ranges[ranges_ix..].binary_search_by_key(&changed.start, |r| r.end_byte) {
                     Ok(ix) | Err(ix) => ix,
                 };
-            let end_ix = ranges_ix
+            let mut end_ix = ranges_ix
                 + match ranges[ranges_ix..].binary_search_by_key(&changed.end, |r| r.start_byte) {
                     Ok(ix) => ix + 1,
                     Err(ix) => ix,
                 };
+
+            // If there are empty ranges, then there may be multiple ranges with the same
+            // start or end. Expand the splice to include any adjacent ranges. That touch
+            // the changed range.
+            while start_ix > 0 {
+                if ranges[start_ix - 1].end_byte == changed.start {
+                    start_ix -= 1;
+                } else {
+                    break;
+                }
+            }
+            while let Some(range) = ranges.get(end_ix) {
+                if range.start_byte == changed.end {
+                    end_ix += 1;
+                } else {
+                    break;
+                }
+            }
+
             if end_ix > start_ix {
                 ranges.splice(start_ix..end_ix, []);
             }
@@ -1850,6 +1869,24 @@ mod tests {
         );
     }
 
+    #[gpui::test]
+    fn test_combined_injections_empty_ranges() {
+        test_edit_sequence(
+            "ERB",
+            &[
+                "
+                    <% if @one %>
+                    <% else %>
+                    <% end %>
+                ",
+                "
+                    <% if @one %>
+                    ˇ<% end %>
+                ",
+            ],
+        );
+    }
+
     #[gpui::test(iterations = 100)]
     fn test_random_syntax_map_edits(mut rng: StdRng) {
         let operations = env::var("OPERATIONS")