editor: Fix adjacent custom highlights interfering with each other (#37912)

Lukas Wirth and Finn Evers created

Release Notes:

- Fixed matching bracket highlighting not highlighting closing brackets
when adjacent to each other

Co-authored-by: Finn Evers <finn@zed.dev>

Change summary

crates/editor/src/display_map.rs                   |  4 +-
crates/editor/src/display_map/custom_highlights.rs | 24 ++++++++-------
2 files changed, 15 insertions(+), 13 deletions(-)

Detailed changes

crates/editor/src/display_map.rs 🔗

@@ -2609,7 +2609,7 @@ pub mod tests {
         );
         language.set_theme(&theme);
 
-        let (text, highlighted_ranges) = marked_text_ranges(r#"constˇ «a»: B = "c «d»""#, false);
+        let (text, highlighted_ranges) = marked_text_ranges(r#"constˇ «a»«:» B = "c «d»""#, false);
 
         let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(language, cx));
         cx.condition(&buffer, |buf, _| !buf.is_parsing()).await;
@@ -2658,7 +2658,7 @@ pub mod tests {
             [
                 ("const ".to_string(), None, None),
                 ("a".to_string(), None, Some(Hsla::blue())),
-                (":".to_string(), Some(Hsla::red()), None),
+                (":".to_string(), Some(Hsla::red()), Some(Hsla::blue())),
                 (" B = ".to_string(), None, None),
                 ("\"c ".to_string(), Some(Hsla::green()), None),
                 ("d".to_string(), Some(Hsla::green()), Some(Hsla::blue())),

crates/editor/src/display_map/custom_highlights.rs 🔗

@@ -25,9 +25,8 @@ pub struct CustomHighlightsChunks<'a> {
 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
 struct HighlightEndpoint {
     offset: usize,
-    is_start: bool,
     tag: HighlightKey,
-    style: HighlightStyle,
+    style: Option<HighlightStyle>,
 }
 
 impl<'a> CustomHighlightsChunks<'a> {
@@ -92,17 +91,20 @@ fn create_highlight_endpoints(
                     break;
                 }
 
+                let start = range.start.to_offset(buffer);
+                let end = range.end.to_offset(buffer);
+                if start == end {
+                    continue;
+                }
                 highlight_endpoints.push(HighlightEndpoint {
-                    offset: range.start.to_offset(buffer),
-                    is_start: true,
+                    offset: start,
                     tag,
-                    style,
+                    style: Some(style),
                 });
                 highlight_endpoints.push(HighlightEndpoint {
-                    offset: range.end.to_offset(buffer),
-                    is_start: false,
+                    offset: end,
                     tag,
-                    style,
+                    style: None,
                 });
             }
         }
@@ -118,8 +120,8 @@ impl<'a> Iterator for CustomHighlightsChunks<'a> {
         let mut next_highlight_endpoint = usize::MAX;
         while let Some(endpoint) = self.highlight_endpoints.peek().copied() {
             if endpoint.offset <= self.offset {
-                if endpoint.is_start {
-                    self.active_highlights.insert(endpoint.tag, endpoint.style);
+                if let Some(style) = endpoint.style {
+                    self.active_highlights.insert(endpoint.tag, style);
                 } else {
                     self.active_highlights.remove(&endpoint.tag);
                 }
@@ -168,6 +170,6 @@ impl Ord for HighlightEndpoint {
     fn cmp(&self, other: &Self) -> cmp::Ordering {
         self.offset
             .cmp(&other.offset)
-            .then_with(|| other.is_start.cmp(&self.is_start))
+            .then_with(|| self.style.is_some().cmp(&other.style.is_some()))
     }
 }