Quick cut of using display point conversion to layout hunks

Julia and Max Brunsfeld created

Co-Authored-By: Max Brunsfeld <max@zed.dev>

Change summary

crates/editor/src/element.rs | 227 +++++++++++++++++--------------------
1 file changed, 106 insertions(+), 121 deletions(-)

Detailed changes

crates/editor/src/element.rs 🔗

@@ -35,7 +35,7 @@ use gpui::{
     WeakViewHandle,
 };
 use json::json;
-use language::{Bias, DiagnosticSeverity, OffsetUtf16, Selection};
+use language::{Bias, DiagnosticSeverity, OffsetUtf16, Point, Selection};
 use project::ProjectPath;
 use settings::{GitGutter, Settings};
 use smallvec::SmallVec;
@@ -52,6 +52,7 @@ use theme::DiffStyle;
 struct DiffHunkLayout {
     visual_range: Range<u32>,
     status: DiffHunkStatus,
+    is_folded: bool,
 }
 
 struct SelectionLayout {
@@ -544,12 +545,12 @@ impl EditorElement {
             gutter_layout: &GutterLayout,
             diff_style: &DiffStyle,
         ) -> Quad {
-            let color = match hunk.status {
-                DiffHunkStatus::Added => diff_style.inserted,
-                DiffHunkStatus::Modified => diff_style.modified,
+            let color = match (hunk.status, hunk.is_folded) {
+                (DiffHunkStatus::Added, false) => diff_style.inserted,
+                (DiffHunkStatus::Modified, false) => diff_style.modified,
 
                 //TODO: This rendering is entirely a horrible hack
-                DiffHunkStatus::Removed => {
+                (DiffHunkStatus::Removed, false) => {
                     let row = hunk.visual_range.start;
 
                     let offset = gutter_layout.line_height / 2.;
@@ -569,6 +570,24 @@ impl EditorElement {
                         corner_radius: 1. * gutter_layout.line_height,
                     };
                 }
+
+                (_, true) => {
+                    let row = hunk.visual_range.start;
+                    let start_y = row as f32 * gutter_layout.line_height - gutter_layout.scroll_top;
+                    let end_y = start_y + gutter_layout.line_height;
+
+                    let width = diff_style.removed_width_em * gutter_layout.line_height;
+                    let highlight_origin = gutter_layout.bounds.origin() + vec2f(-width, start_y);
+                    let highlight_size = vec2f(width * 2., end_y - start_y);
+                    let highlight_bounds = RectF::new(highlight_origin, highlight_size);
+
+                    return Quad {
+                        bounds: highlight_bounds,
+                        background: Some(diff_style.modified),
+                        border: Border::new(0., Color::transparent_black()),
+                        corner_radius: 1. * gutter_layout.line_height,
+                    };
+                }
             };
 
             let start_row = hunk.visual_range.start;
@@ -986,47 +1005,6 @@ impl EditorElement {
             .width()
     }
 
-    //-> (layout, buffer row advancement)
-    fn layout_diff_hunk(
-        hunk: &DiffHunk<u32>,
-        start_row: u32,
-        buffer_rows: &mut std::iter::Peekable<impl Iterator<Item = (usize, Option<u32>)>>,
-    ) -> (Option<DiffHunkLayout>, u32) {
-        //`buffer_rows` should start with a row which is contained in the hunk's buffer range
-        let first_buffer_rows = match buffer_rows.peek() {
-            Some(first_buffer_rows) => first_buffer_rows,
-            None => return (None, 0),
-        };
-
-        //The `usize` field is 1-index so we have to sub to move it into 0-offset to match actual rows
-        let visual_start = start_row + first_buffer_rows.0 as u32 - 1;
-
-        let mut visual_count = 0;
-        let mut buffer_row_advancement = 0;
-        while let Some(&buffer_row) = buffer_rows.peek() {
-            if let (_, Some(buffer_row)) = buffer_row {
-                buffer_row_advancement += 1;
-                if buffer_row == hunk.buffer_range.end {
-                    visual_count += 1;
-                    break;
-                } else if buffer_row > hunk.buffer_range.end {
-                    break;
-                }
-                visual_count += 1;
-            } else {
-                visual_count += 1;
-            }
-
-            buffer_rows.next();
-        }
-
-        let layout = DiffHunkLayout {
-            visual_range: visual_start..visual_start + visual_count,
-            status: hunk.status(),
-        };
-        (Some(layout), buffer_row_advancement)
-    }
-
     //Folds contained in a hunk are ignored apart from shrinking visual size
     //If a fold contains any hunks then that fold line is marked as modified
     fn layout_git_gutters(
@@ -1034,87 +1012,94 @@ impl EditorElement {
         rows: Range<u32>,
         snapshot: &EditorSnapshot,
     ) -> Vec<DiffHunkLayout> {
-        let buffer_rows = snapshot.buffer_rows(rows.start);
-        let start_actual_row = match buffer_rows
-            .clone()
-            .take((rows.end - rows.start) as usize)
-            .find_map(|b| b)
-        {
-            Some(start_actual_row) => start_actual_row,
-            None => return Vec::new(),
-        };
-
-        //Get all hunks after our starting actual buffer row
-        //The loop is in terms of visual buffer rows so we simply
-        //return before touching any hunks past the end of the view
-        let mut diff_hunks = snapshot
-            .buffer_snapshot
-            .git_diff_hunks_in_range(start_actual_row..u32::MAX)
-            .peekable();
-
-        //Some number followed by Nones for wrapped lines
-        //Jump in number for folded lines
-        let mut buffer_rows = buffer_rows
-            .take((rows.end - rows.start) as usize)
-            .enumerate()
-            .peekable();
+        let start_row = DisplayPoint::new(rows.start, 0).to_point(snapshot).row;
+        let end_row = DisplayPoint::new(rows.end, 0).to_point(snapshot).row;
 
         let mut layouts = Vec::new();
-        let mut previous_buffer_row = None;
-
-        while let Some((idx, buffer_row)) = buffer_rows.next() {
-            let buffer_row = match buffer_row {
-                Some(buffer_row) => buffer_row,
-                None => continue,
-            };
-
-            let is_start_of_fold = previous_buffer_row
-                .map(|prev| buffer_row > prev + 1)
-                .unwrap_or(false);
-            previous_buffer_row = Some(buffer_row);
-
-            if is_start_of_fold {
-                //Consume all hunks within fold
-                let mut consumed_hunks = false;
-                while let Some(hunk) = diff_hunks.peek() {
-                    let is_past = hunk.buffer_range.start > buffer_row;
-                    let is_removal = hunk.status() == DiffHunkStatus::Removed;
-                    let is_on_next_line = hunk.buffer_range.start == buffer_row + 1;
-                    let is_removal_inside = is_removal && is_on_next_line;
-
-                    if is_past && !is_removal_inside {
-                        break;
-                    }
-                    diff_hunks.next();
-                    consumed_hunks = true;
-                }
-
-                //And mark fold as modified if there were any
-                if consumed_hunks {
-                    let current_visual_row = rows.start + idx as u32 - 1;
-                    layouts.push(DiffHunkLayout {
-                        visual_range: current_visual_row..current_visual_row + 1,
-                        status: DiffHunkStatus::Modified,
-                    });
-                }
-            } else if let Some(hunk) = diff_hunks.peek() {
-                let row_inside_hunk = hunk.buffer_range.contains(&buffer_row);
-                let starts_on_row = hunk.buffer_range.start == buffer_row;
-                if row_inside_hunk || starts_on_row {
-                    let (layout, buffer_row_advancement) =
-                        Self::layout_diff_hunk(hunk, rows.start, &mut buffer_rows);
-                    previous_buffer_row = Some(buffer_row + buffer_row_advancement);
-
-                    if let Some(layout) = layout {
-                        layouts.push(layout);
-                    }
+        for hunk in snapshot
+            .buffer_snapshot
+            .git_diff_hunks_in_range(start_row..end_row)
+        {
+            let start = Point::new(hunk.buffer_range.start, 0).to_display_point(snapshot);
+            let end = Point::new(hunk.buffer_range.end, 0).to_display_point(snapshot);
+            let is_folded = start == end && snapshot.is_line_folded(start.row());
 
-                    diff_hunks.next();
-                }
+            if let Some(hunk) = layouts.last_mut() {
+                //
             }
+
+            layouts.push(DiffHunkLayout {
+                visual_range: start.row()..end.row(),
+                status: hunk.status(),
+                is_folded,
+            });
         }
 
-        layouts
+        return layouts;
+
+        //Some number followed by Nones for wrapped lines
+        //Jump in number for folded lines
+        // let mut buffer_rows = buffer_rows
+        //     .take((rows.end - rows.start) as usize)
+        //     .enumerate()
+        //     .peekable();
+
+        // let mut layouts = Vec::new();
+        // let mut previous_buffer_row = None;
+
+        // while let Some((idx, buffer_row)) = buffer_rows.next() {
+        //     let buffer_row = match buffer_row {
+        //         Some(buffer_row) => buffer_row,
+        //         None => continue,
+        //     };
+
+        //     let is_start_of_fold = previous_buffer_row
+        //         .map(|prev| buffer_row > prev + 1)
+        //         .unwrap_or(false);
+        //     previous_buffer_row = Some(buffer_row);
+
+        //     if is_start_of_fold {
+        //         //Consume all hunks within fold
+        //         let mut consumed_hunks = false;
+        //         while let Some(hunk) = diff_hunks.peek() {
+        //             let is_past = hunk.buffer_range.start > buffer_row;
+        //             let is_removal = hunk.status() == DiffHunkStatus::Removed;
+        //             let is_on_next_line = hunk.buffer_range.start == buffer_row + 1;
+        //             let is_removal_inside = is_removal && is_on_next_line;
+
+        //             if is_past && !is_removal_inside {
+        //                 break;
+        //             }
+        //             diff_hunks.next();
+        //             consumed_hunks = true;
+        //         }
+
+        //         //And mark fold as modified if there were any
+        //         if consumed_hunks {
+        //             let current_visual_row = rows.start + idx as u32 - 1;
+        //             layouts.push(DiffHunkLayout {
+        //                 visual_range: current_visual_row..current_visual_row + 1,
+        //                 status: DiffHunkStatus::Modified,
+        //             });
+        //         }
+        //     } else if let Some(hunk) = diff_hunks.peek() {
+        //         let row_inside_hunk = hunk.buffer_range.contains(&buffer_row);
+        //         let starts_on_row = hunk.buffer_range.start == buffer_row;
+        //         if row_inside_hunk || starts_on_row {
+        //             let (layout, buffer_row_advancement) =
+        //                 Self::layout_diff_hunk(hunk, rows.start, &mut buffer_rows);
+        //             previous_buffer_row = Some(buffer_row + buffer_row_advancement);
+
+        //             if let Some(layout) = layout {
+        //                 layouts.push(layout);
+        //             }
+
+        //             diff_hunks.next();
+        //         }
+        //     }
+        // }
+
+        // layouts
     }
 
     fn layout_line_numbers(