Autoclose bracket only if next char is whitespace or the end of a pair

Antonio Scandurra created

Change summary

crates/editor/src/editor.rs | 38 +++++++++++++++++++++++++++++++++++---
1 file changed, 35 insertions(+), 3 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -1850,11 +1850,24 @@ impl Editor {
                     )
                 });
                 pair.and_then(|pair| {
-                    let should_autoclose = selections[1..].iter().all(|selection| {
-                        snapshot.contains_str_at(
+                    let should_autoclose = selections.iter().all(|selection| {
+                        // Ensure all selections are parked at the end of a pair start.
+                        if snapshot.contains_str_at(
                             selection.start.saturating_sub(pair.start.len()),
                             &pair.start,
-                        )
+                        ) {
+                            // Autoclose only if the next character is a whitespace or a pair end
+                            // (possibly a different one from the pair we are inserting).
+                            snapshot
+                                .chars_at(selection.start)
+                                .next()
+                                .map_or(true, |ch| ch.is_whitespace())
+                                || language.brackets().iter().any(|pair| {
+                                    snapshot.contains_str_at(selection.start, &pair.end)
+                                })
+                        } else {
+                            false
+                        }
                     });
 
                     if should_autoclose {
@@ -3201,6 +3214,11 @@ impl Editor {
         }
     }
 
+    pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
+        self.buffer
+            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
+    }
+
     pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let mut selections = self.local_selections::<Point>(cx);
@@ -8083,6 +8101,20 @@ mod tests {
                 "
                 .unindent()
             );
+
+            view.finalize_last_transaction(cx);
+            view.select_display_ranges(&[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], cx);
+            view.handle_input(&Input("{".to_string()), cx);
+            assert_eq!(
+                view.text(cx),
+                "
+                {a
+
+                /*
+                *
+                "
+                .unindent()
+            );
         });
     }