Show fold indicators (#3334)

Antonio Scandurra created

Release Notes:

- N/A

Change summary

crates/editor2/src/display_map.rs          |   6 
crates/editor2/src/display_map/fold_map.rs | 105 ++-
crates/editor2/src/editor.rs               | 148 +--
crates/editor2/src/element.rs              | 781 +++++++++++------------
crates/editor2/src/git.rs                  |   6 
crates/gpui2/src/element.rs                |  46 +
crates/gpui2/src/elements/div.rs           |  62 +
crates/gpui2/src/elements/uniform_list.rs  |  17 
crates/gpui2/src/view.rs                   |  27 
crates/gpui2/src/window.rs                 |   8 
10 files changed, 621 insertions(+), 585 deletions(-)

Detailed changes

crates/editor2/src/display_map.rs 🔗

@@ -31,7 +31,7 @@ pub use block_map::{
     BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock, TransformBlock,
 };
 
-pub use self::fold_map::FoldPoint;
+pub use self::fold_map::{Fold, FoldPoint};
 pub use self::inlay_map::{Inlay, InlayOffset, InlayPoint};
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -124,7 +124,7 @@ impl DisplayMap {
         self.fold(
             other
                 .folds_in_range(0..other.buffer_snapshot.len())
-                .map(|fold| fold.to_offset(&other.buffer_snapshot)),
+                .map(|fold| fold.range.to_offset(&other.buffer_snapshot)),
             cx,
         );
     }
@@ -723,7 +723,7 @@ impl DisplaySnapshot {
         DisplayPoint(point)
     }
 
-    pub fn folds_in_range<T>(&self, range: Range<T>) -> impl Iterator<Item = &Range<Anchor>>
+    pub fn folds_in_range<T>(&self, range: Range<T>) -> impl Iterator<Item = &Fold>
     where
         T: ToOffset,
     {

crates/editor2/src/display_map/fold_map.rs 🔗

@@ -3,15 +3,16 @@ use super::{
     Highlights,
 };
 use crate::{Anchor, AnchorRangeExt, MultiBufferSnapshot, ToOffset};
-use gpui::{HighlightStyle, Hsla};
+use gpui::{ElementId, HighlightStyle, Hsla};
 use language::{Chunk, Edit, Point, TextSummary};
 use std::{
     any::TypeId,
     cmp::{self, Ordering},
     iter,
-    ops::{Add, AddAssign, Range, Sub},
+    ops::{Add, AddAssign, Deref, DerefMut, Range, Sub},
 };
 use sum_tree::{Bias, Cursor, FilterCursor, SumTree};
+use util::post_inc;
 
 #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
 pub struct FoldPoint(pub Point);
@@ -90,12 +91,16 @@ impl<'a> FoldMapWriter<'a> {
             }
 
             // For now, ignore any ranges that span an excerpt boundary.
-            let fold = Fold(buffer.anchor_after(range.start)..buffer.anchor_before(range.end));
-            if fold.0.start.excerpt_id != fold.0.end.excerpt_id {
+            let fold_range =
+                FoldRange(buffer.anchor_after(range.start)..buffer.anchor_before(range.end));
+            if fold_range.0.start.excerpt_id != fold_range.0.end.excerpt_id {
                 continue;
             }
 
-            folds.push(fold);
+            folds.push(Fold {
+                id: FoldId(post_inc(&mut self.0.next_fold_id.0)),
+                range: fold_range,
+            });
 
             let inlay_range =
                 snapshot.to_inlay_offset(range.start)..snapshot.to_inlay_offset(range.end);
@@ -106,13 +111,13 @@ impl<'a> FoldMapWriter<'a> {
         }
 
         let buffer = &snapshot.buffer;
-        folds.sort_unstable_by(|a, b| sum_tree::SeekTarget::cmp(a, b, buffer));
+        folds.sort_unstable_by(|a, b| sum_tree::SeekTarget::cmp(&a.range, &b.range, buffer));
 
         self.0.snapshot.folds = {
             let mut new_tree = SumTree::new();
-            let mut cursor = self.0.snapshot.folds.cursor::<Fold>();
+            let mut cursor = self.0.snapshot.folds.cursor::<FoldRange>();
             for fold in folds {
-                new_tree.append(cursor.slice(&fold, Bias::Right, buffer), buffer);
+                new_tree.append(cursor.slice(&fold.range, Bias::Right, buffer), buffer);
                 new_tree.push(fold, buffer);
             }
             new_tree.append(cursor.suffix(buffer), buffer);
@@ -138,7 +143,8 @@ impl<'a> FoldMapWriter<'a> {
             let mut folds_cursor =
                 intersecting_folds(&snapshot, &self.0.snapshot.folds, range, inclusive);
             while let Some(fold) = folds_cursor.item() {
-                let offset_range = fold.0.start.to_offset(buffer)..fold.0.end.to_offset(buffer);
+                let offset_range =
+                    fold.range.start.to_offset(buffer)..fold.range.end.to_offset(buffer);
                 if offset_range.end > offset_range.start {
                     let inlay_range = snapshot.to_inlay_offset(offset_range.start)
                         ..snapshot.to_inlay_offset(offset_range.end);
@@ -175,6 +181,7 @@ impl<'a> FoldMapWriter<'a> {
 pub struct FoldMap {
     snapshot: FoldSnapshot,
     ellipses_color: Option<Hsla>,
+    next_fold_id: FoldId,
 }
 
 impl FoldMap {
@@ -197,6 +204,7 @@ impl FoldMap {
                 ellipses_color: None,
             },
             ellipses_color: None,
+            next_fold_id: FoldId::default(),
         };
         let snapshot = this.snapshot.clone();
         (this, snapshot)
@@ -242,8 +250,8 @@ impl FoldMap {
             while let Some(fold) = folds.next() {
                 if let Some(next_fold) = folds.peek() {
                     let comparison = fold
-                        .0
-                        .cmp(&next_fold.0, &self.snapshot.inlay_snapshot.buffer);
+                        .range
+                        .cmp(&next_fold.range, &self.snapshot.inlay_snapshot.buffer);
                     assert!(comparison.is_le());
                 }
             }
@@ -304,9 +312,9 @@ impl FoldMap {
                 let anchor = inlay_snapshot
                     .buffer
                     .anchor_before(inlay_snapshot.to_buffer_offset(edit.new.start));
-                let mut folds_cursor = self.snapshot.folds.cursor::<Fold>();
+                let mut folds_cursor = self.snapshot.folds.cursor::<FoldRange>();
                 folds_cursor.seek(
-                    &Fold(anchor..Anchor::max()),
+                    &FoldRange(anchor..Anchor::max()),
                     Bias::Left,
                     &inlay_snapshot.buffer,
                 );
@@ -315,8 +323,8 @@ impl FoldMap {
                     let inlay_snapshot = &inlay_snapshot;
                     move || {
                         let item = folds_cursor.item().map(|f| {
-                            let buffer_start = f.0.start.to_offset(&inlay_snapshot.buffer);
-                            let buffer_end = f.0.end.to_offset(&inlay_snapshot.buffer);
+                            let buffer_start = f.range.start.to_offset(&inlay_snapshot.buffer);
+                            let buffer_end = f.range.end.to_offset(&inlay_snapshot.buffer);
                             inlay_snapshot.to_inlay_offset(buffer_start)
                                 ..inlay_snapshot.to_inlay_offset(buffer_end)
                         });
@@ -596,13 +604,13 @@ impl FoldSnapshot {
         self.transforms.summary().output.longest_row
     }
 
-    pub fn folds_in_range<T>(&self, range: Range<T>) -> impl Iterator<Item = &Range<Anchor>>
+    pub fn folds_in_range<T>(&self, range: Range<T>) -> impl Iterator<Item = &Fold>
     where
         T: ToOffset,
     {
         let mut folds = intersecting_folds(&self.inlay_snapshot, &self.folds, range, false);
         iter::from_fn(move || {
-            let item = folds.item().map(|f| &f.0);
+            let item = folds.item();
             folds.next(&self.inlay_snapshot.buffer);
             item
         })
@@ -830,10 +838,39 @@ impl sum_tree::Summary for TransformSummary {
     }
 }
 
-#[derive(Clone, Debug)]
-struct Fold(Range<Anchor>);
+#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
+pub struct FoldId(usize);
+
+impl Into<ElementId> for FoldId {
+    fn into(self) -> ElementId {
+        ElementId::Integer(self.0)
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Fold {
+    pub id: FoldId,
+    pub range: FoldRange,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct FoldRange(Range<Anchor>);
+
+impl Deref for FoldRange {
+    type Target = Range<Anchor>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl DerefMut for FoldRange {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
 
-impl Default for Fold {
+impl Default for FoldRange {
     fn default() -> Self {
         Self(Anchor::min()..Anchor::max())
     }
@@ -844,17 +881,17 @@ impl sum_tree::Item for Fold {
 
     fn summary(&self) -> Self::Summary {
         FoldSummary {
-            start: self.0.start.clone(),
-            end: self.0.end.clone(),
-            min_start: self.0.start.clone(),
-            max_end: self.0.end.clone(),
+            start: self.range.start.clone(),
+            end: self.range.end.clone(),
+            min_start: self.range.start.clone(),
+            max_end: self.range.end.clone(),
             count: 1,
         }
     }
 }
 
 #[derive(Clone, Debug)]
-struct FoldSummary {
+pub struct FoldSummary {
     start: Anchor,
     end: Anchor,
     min_start: Anchor,
@@ -900,14 +937,14 @@ impl sum_tree::Summary for FoldSummary {
     }
 }
 
-impl<'a> sum_tree::Dimension<'a, FoldSummary> for Fold {
+impl<'a> sum_tree::Dimension<'a, FoldSummary> for FoldRange {
     fn add_summary(&mut self, summary: &'a FoldSummary, _: &MultiBufferSnapshot) {
         self.0.start = summary.start.clone();
         self.0.end = summary.end.clone();
     }
 }
 
-impl<'a> sum_tree::SeekTarget<'a, FoldSummary, Fold> for Fold {
+impl<'a> sum_tree::SeekTarget<'a, FoldSummary, FoldRange> for FoldRange {
     fn cmp(&self, other: &Self, buffer: &MultiBufferSnapshot) -> Ordering {
         self.0.cmp(&other.0, buffer)
     }
@@ -1321,7 +1358,10 @@ mod tests {
         let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]);
         let fold_ranges = snapshot
             .folds_in_range(Point::new(1, 0)..Point::new(1, 3))
-            .map(|fold| fold.start.to_point(&buffer_snapshot)..fold.end.to_point(&buffer_snapshot))
+            .map(|fold| {
+                fold.range.start.to_point(&buffer_snapshot)
+                    ..fold.range.end.to_point(&buffer_snapshot)
+            })
             .collect::<Vec<_>>();
         assert_eq!(
             fold_ranges,
@@ -1553,10 +1593,9 @@ mod tests {
                     .filter(|fold| {
                         let start = buffer_snapshot.anchor_before(start);
                         let end = buffer_snapshot.anchor_after(end);
-                        start.cmp(&fold.0.end, &buffer_snapshot) == Ordering::Less
-                            && end.cmp(&fold.0.start, &buffer_snapshot) == Ordering::Greater
+                        start.cmp(&fold.range.end, &buffer_snapshot) == Ordering::Less
+                            && end.cmp(&fold.range.start, &buffer_snapshot) == Ordering::Greater
                     })
-                    .map(|fold| fold.0)
                     .collect::<Vec<_>>();
 
                 assert_eq!(
@@ -1639,10 +1678,10 @@ mod tests {
             let buffer = &inlay_snapshot.buffer;
             let mut folds = self.snapshot.folds.items(buffer);
             // Ensure sorting doesn't change how folds get merged and displayed.
-            folds.sort_by(|a, b| a.0.cmp(&b.0, buffer));
+            folds.sort_by(|a, b| a.range.cmp(&b.range, buffer));
             let mut fold_ranges = folds
                 .iter()
-                .map(|fold| fold.0.start.to_offset(buffer)..fold.0.end.to_offset(buffer))
+                .map(|fold| fold.range.start.to_offset(buffer)..fold.range.end.to_offset(buffer))
                 .peekable();
 
             let mut merged_ranges = Vec::new();

crates/editor2/src/editor.rs 🔗

@@ -39,12 +39,12 @@ use futures::FutureExt;
 use fuzzy::{StringMatch, StringMatchCandidate};
 use git::diff_hunk_to_display;
 use gpui::{
-    action, actions, div, point, prelude::*, px, relative, rems, render_view, size, uniform_list,
-    AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem,
-    Component, Context, EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight,
-    HighlightStyle, Hsla, InputHandler, KeyContext, Model, MouseButton, ParentComponent, Pixels,
-    Render, Styled, Subscription, Task, TextStyle, UniformListScrollHandle, View, ViewContext,
-    VisualContext, WeakView, WindowContext,
+    action, actions, div, point, prelude::*, px, relative, rems, size, uniform_list, AnyElement,
+    AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context,
+    EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight, HighlightStyle, Hsla,
+    InputHandler, KeyContext, Model, MouseButton, ParentComponent, Pixels, Render, Styled,
+    Subscription, Task, TextStyle, UniformListScrollHandle, View, ViewContext, VisualContext,
+    WeakView, WindowContext,
 };
 use highlight_matching_bracket::refresh_matching_bracket_highlights;
 use hover_popover::{hide_hover, HoverState};
@@ -4372,69 +4372,42 @@ impl Editor {
         }
     }
 
-    //     pub fn render_fold_indicators(
-    //         &self,
-    //         fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
-    //         style: &EditorStyle,
-    //         gutter_hovered: bool,
-    //         line_height: f32,
-    //         gutter_margin: f32,
-    //         cx: &mut ViewContext<Self>,
-    //     ) -> Vec<Option<AnyElement<Self>>> {
-    //         enum FoldIndicators {}
-
-    //         let style = style.folds.clone();
-
-    //         fold_data
-    //             .iter()
-    //             .enumerate()
-    //             .map(|(ix, fold_data)| {
-    //                 fold_data
-    //                     .map(|(fold_status, buffer_row, active)| {
-    //                         (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
-    //                             MouseEventHandler::new::<FoldIndicators, _>(
-    //                                 ix as usize,
-    //                                 cx,
-    //                                 |mouse_state, _| {
-    //                                     Svg::new(match fold_status {
-    //                                         FoldStatus::Folded => style.folded_icon.clone(),
-    //                                         FoldStatus::Foldable => style.foldable_icon.clone(),
-    //                                     })
-    //                                     .with_color(
-    //                                         style
-    //                                             .indicator
-    //                                             .in_state(fold_status == FoldStatus::Folded)
-    //                                             .style_for(mouse_state)
-    //                                             .color,
-    //                                     )
-    //                                     .constrained()
-    //                                     .with_width(gutter_margin * style.icon_margin_scale)
-    //                                     .aligned()
-    //                                     .constrained()
-    //                                     .with_height(line_height)
-    //                                     .with_width(gutter_margin)
-    //                                     .aligned()
-    //                                 },
-    //                             )
-    //                             .with_cursor_style(CursorStyle::PointingHand)
-    //                             .with_padding(Padding::uniform(3.))
-    //                             .on_click(MouseButton::Left, {
-    //                                 move |_, editor, cx| match fold_status {
-    //                                     FoldStatus::Folded => {
-    //                                         editor.unfold_at(&UnfoldAt { buffer_row }, cx);
-    //                                     }
-    //                                     FoldStatus::Foldable => {
-    //                                         editor.fold_at(&FoldAt { buffer_row }, cx);
-    //                                     }
-    //                                 }
-    //                             })
-    //                             .into_any()
-    //                         })
-    //                     })
-    //                     .flatten()
-    //             })
-    //             .collect()
-    //     }
+    pub fn render_fold_indicators(
+        &self,
+        fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
+        style: &EditorStyle,
+        gutter_hovered: bool,
+        line_height: Pixels,
+        gutter_margin: Pixels,
+        cx: &mut ViewContext<Self>,
+    ) -> Vec<Option<AnyElement<Self>>> {
+        fold_data
+            .iter()
+            .enumerate()
+            .map(|(ix, fold_data)| {
+                fold_data
+                    .map(|(fold_status, buffer_row, active)| {
+                        (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
+                            let icon = match fold_status {
+                                FoldStatus::Folded => ui::Icon::ChevronRight,
+                                FoldStatus::Foldable => ui::Icon::ChevronDown,
+                            };
+                            IconButton::new(ix as usize, icon)
+                                .on_click(move |editor: &mut Editor, cx| match fold_status {
+                                    FoldStatus::Folded => {
+                                        editor.unfold_at(&UnfoldAt { buffer_row }, cx);
+                                    }
+                                    FoldStatus::Foldable => {
+                                        editor.fold_at(&FoldAt { buffer_row }, cx);
+                                    }
+                                })
+                                .render()
+                        })
+                    })
+                    .flatten()
+            })
+            .collect()
+    }
 
     pub fn context_menu_visible(&self) -> bool {
         self.context_menu
@@ -5330,8 +5303,8 @@ impl Editor {
                         buffer.anchor_before(range_to_move.start)
                             ..buffer.anchor_after(range_to_move.end),
                     ) {
-                        let mut start = fold.start.to_point(&buffer);
-                        let mut end = fold.end.to_point(&buffer);
+                        let mut start = fold.range.start.to_point(&buffer);
+                        let mut end = fold.range.end.to_point(&buffer);
                         start.row -= row_delta;
                         end.row -= row_delta;
                         refold_ranges.push(start..end);
@@ -5421,8 +5394,8 @@ impl Editor {
                         buffer.anchor_before(range_to_move.start)
                             ..buffer.anchor_after(range_to_move.end),
                     ) {
-                        let mut start = fold.start.to_point(&buffer);
-                        let mut end = fold.end.to_point(&buffer);
+                        let mut start = fold.range.start.to_point(&buffer);
+                        let mut end = fold.range.end.to_point(&buffer);
                         start.row += row_delta;
                         end.row += row_delta;
                         refold_ranges.push(start..end);
@@ -7804,25 +7777,18 @@ impl Editor {
                                     }
                                     div()
                                         .pl(cx.anchor_x)
-                                        .child(render_view(
+                                        .child(rename_editor.render_with(EditorElement::new(
                                             &rename_editor,
-                                            EditorElement::new(
-                                                &rename_editor,
-                                                EditorStyle {
-                                                    background: cx.theme().system().transparent,
-                                                    local_player: cx.editor_style.local_player,
-                                                    text: text_style,
-                                                    scrollbar_width: cx
-                                                        .editor_style
-                                                        .scrollbar_width,
-                                                    syntax: cx.editor_style.syntax.clone(),
-                                                    diagnostic_style: cx
-                                                        .editor_style
-                                                        .diagnostic_style
-                                                        .clone(),
-                                                },
-                                            ),
-                                        ))
+                                            EditorStyle {
+                                                background: cx.theme().system().transparent,
+                                                local_player: cx.editor_style.local_player,
+                                                text: text_style,
+                                                scrollbar_width: cx.editor_style.scrollbar_width,
+                                                syntax: cx.editor_style.syntax.clone(),
+                                                diagnostic_style:
+                                                    cx.editor_style.diagnostic_style.clone(),
+                                            },
+                                        )))
                                         .render()
                                 }
                             }),

crates/editor2/src/element.rs 🔗

@@ -18,11 +18,12 @@ use crate::{
 use anyhow::Result;
 use collections::{BTreeMap, HashMap};
 use gpui::{
-    point, px, relative, size, transparent_black, Action, AnyElement, AvailableSpace, BorrowWindow,
-    Bounds, Component, ContentMask, Corners, DispatchPhase, Edges, Element, ElementId,
-    ElementInputHandler, Entity, EntityId, Hsla, Line, MouseButton, MouseDownEvent, MouseMoveEvent,
-    MouseUpEvent, ParentComponent, Pixels, ScrollWheelEvent, Size, Style, Styled, TextRun,
-    TextStyle, View, ViewContext, WindowContext,
+    div, point, px, relative, size, transparent_black, Action, AnyElement, AvailableSpace,
+    BorrowWindow, Bounds, Component, ContentMask, Corners, DispatchPhase, Edges, Element,
+    ElementId, ElementInputHandler, Entity, EntityId, Hsla, InteractiveComponent, Line,
+    MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentComponent, Pixels,
+    ScrollWheelEvent, Size, StatefulInteractiveComponent, Style, Styled, TextRun, TextStyle, View,
+    ViewContext, WindowContext,
 };
 use itertools::Itertools;
 use language::language_settings::ShowWhitespaceSetting;
@@ -487,23 +488,26 @@ impl EditorElement {
             }
         }
 
-        // todo!("fold indicators")
-        // for (ix, fold_indicator) in layout.fold_indicators.iter_mut().enumerate() {
-        //     if let Some(indicator) = fold_indicator.as_mut() {
-        //         let position = point(
-        //             bounds.width() - layout.gutter_padding,
-        //             ix as f32 * line_height - (scroll_top % line_height),
-        //         );
-        //         let centering_offset = point(
-        //             (layout.gutter_padding + layout.gutter_margin - indicator.size().x) / 2.,
-        //             (line_height - indicator.size().y) / 2.,
-        //         );
-
-        //         let indicator_origin = bounds.origin + position + centering_offset;
+        for (ix, fold_indicator) in layout.fold_indicators.iter_mut().enumerate() {
+            if let Some(fold_indicator) = fold_indicator.as_mut() {
+                let available_space = size(
+                    AvailableSpace::MinContent,
+                    AvailableSpace::Definite(line_height * 0.55),
+                );
+                let fold_indicator_size = fold_indicator.measure(available_space, editor, cx);
 
-        //         indicator.paint(indicator_origin, visible_bounds, editor, cx);
-        //     }
-        // }
+                let position = point(
+                    bounds.size.width - layout.gutter_padding,
+                    ix as f32 * line_height - (scroll_top % line_height),
+                );
+                let centering_offset = point(
+                    (layout.gutter_padding + layout.gutter_margin - fold_indicator_size.width) / 2.,
+                    (line_height - fold_indicator_size.height) / 2.,
+                );
+                let origin = bounds.origin + position + centering_offset;
+                fold_indicator.draw(origin, available_space, editor, cx);
+            }
+        }
 
         if let Some(indicator) = layout.code_actions_indicator.as_mut() {
             let available_space = size(
@@ -612,311 +616,341 @@ impl EditorElement {
 
     fn paint_text(
         &mut self,
-        bounds: Bounds<Pixels>,
+        text_bounds: Bounds<Pixels>,
         layout: &mut LayoutState,
         editor: &mut Editor,
         cx: &mut ViewContext<Editor>,
     ) {
         let scroll_position = layout.position_map.snapshot.scroll_position();
         let start_row = layout.visible_display_row_range.start;
-        let scroll_top = scroll_position.y * layout.position_map.line_height;
-        let max_glyph_width = layout.position_map.em_width;
-        let scroll_left = scroll_position.x * max_glyph_width;
-        let content_origin = bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
+        let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
         let line_end_overshoot = 0.15 * layout.position_map.line_height;
         let whitespace_setting = editor.buffer.read(cx).settings_at(0, cx).show_whitespaces;
 
-        cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
-            // todo!("cursor region")
-            // cx.scene().push_cursor_region(CursorRegion {
-            //     bounds,
-            //     style: if !editor.link_go_to_definition_state.definitions.is_empty {
-            //         CursorStyle::PointingHand
-            //     } else {
-            //         CursorStyle::IBeam
-            //     },
-            // });
-
-            // todo!("fold ranges")
-            // let fold_corner_radius =
-            //     self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height;
-            // for (id, range, color) in layout.fold_ranges.iter() {
-            //     self.paint_highlighted_range(
-            //         range.clone(),
-            //         *color,
-            //         fold_corner_radius,
-            //         fold_corner_radius * 2.,
-            //         layout,
-            //         content_origin,
-            //         scroll_top,
-            //         scroll_left,
-            //         bounds,
-            //         cx,
-            //     );
-
-            //     for bound in range_to_bounds(
-            //         &range,
-            //         content_origin,
-            //         scroll_left,
-            //         scroll_top,
-            //         &layout.visible_display_row_range,
-            //         line_end_overshoot,
-            //         &layout.position_map,
-            //     ) {
-            //         cx.scene().push_cursor_region(CursorRegion {
-            //             bounds: bound,
-            //             style: CursorStyle::PointingHand,
-            //         });
-
-            //         let display_row = range.start.row();
-
-            //         let buffer_row = DisplayPoint::new(display_row, 0)
-            //             .to_point(&layout.position_map.snapshot.display_snapshot)
-            //             .row;
-
-            //         let view_id = cx.view_id();
-            //         cx.scene().push_mouse_region(
-            //             MouseRegion::new::<FoldMarkers>(view_id, *id as usize, bound)
-            //                 .on_click(MouseButton::Left, move |_, editor: &mut Editor, cx| {
-            //                     editor.unfold_at(&UnfoldAt { buffer_row }, cx)
-            //                 })
-            //                 .with_notify_on_hover(true)
-            //                 .with_notify_on_click(true),
-            //         )
-            //     }
-            // }
-
-            for (range, color) in &layout.highlighted_ranges {
-                self.paint_highlighted_range(
-                    range.clone(),
-                    *color,
-                    Pixels::ZERO,
-                    line_end_overshoot,
-                    layout,
-                    content_origin,
-                    scroll_top,
-                    scroll_left,
-                    bounds,
-                    cx,
-                );
-            }
+        cx.with_content_mask(
+            Some(ContentMask {
+                bounds: text_bounds,
+            }),
+            |cx| {
+                // todo!("cursor region")
+                // cx.scene().push_cursor_region(CursorRegion {
+                //     bounds,
+                //     style: if !editor.link_go_to_definition_state.definitions.is_empty {
+                //         CursorStyle::PointingHand
+                //     } else {
+                //         CursorStyle::IBeam
+                //     },
+                // });
+
+                let fold_corner_radius = 0.15 * layout.position_map.line_height;
+                cx.with_element_id(Some("folds"), |cx| {
+                    let snapshot = &layout.position_map.snapshot;
+                    for fold in snapshot.folds_in_range(layout.visible_anchor_range.clone()) {
+                        let fold_range = fold.range.clone();
+                        let display_range = fold.range.start.to_display_point(&snapshot)
+                            ..fold.range.end.to_display_point(&snapshot);
+                        debug_assert_eq!(display_range.start.row(), display_range.end.row());
+                        let row = display_range.start.row();
+
+                        let line_layout = &layout.position_map.line_layouts
+                            [(row - layout.visible_display_row_range.start) as usize]
+                            .line;
+                        let start_x = content_origin.x
+                            + line_layout.x_for_index(display_range.start.column() as usize)
+                            - layout.position_map.scroll_position.x;
+                        let start_y = content_origin.y
+                            + row as f32 * layout.position_map.line_height
+                            - layout.position_map.scroll_position.y;
+                        let end_x = content_origin.x
+                            + line_layout.x_for_index(display_range.end.column() as usize)
+                            - layout.position_map.scroll_position.x;
+
+                        let fold_bounds = Bounds {
+                            origin: point(start_x, start_y),
+                            size: size(end_x - start_x, layout.position_map.line_height),
+                        };
 
-            let mut cursors = SmallVec::<[Cursor; 32]>::new();
-            let corner_radius = 0.15 * layout.position_map.line_height;
-            let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
+                        let fold_background = cx.with_z_index(1, |cx| {
+                            div()
+                                .id(fold.id)
+                                .size_full()
+                                .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
+                                .on_click(move |editor: &mut Editor, _, cx| {
+                                    editor.unfold_ranges(
+                                        [fold_range.start..fold_range.end],
+                                        true,
+                                        false,
+                                        cx,
+                                    );
+                                    cx.stop_propagation();
+                                })
+                                .draw(
+                                    fold_bounds.origin,
+                                    fold_bounds.size,
+                                    editor,
+                                    cx,
+                                    |fold_element_state, cx| {
+                                        if fold_element_state.is_active() {
+                                            gpui::blue()
+                                        } else if fold_bounds.contains_point(&cx.mouse_position()) {
+                                            gpui::black()
+                                        } else {
+                                            gpui::red()
+                                        }
+                                    },
+                                )
+                        });
+
+                        self.paint_highlighted_range(
+                            display_range.clone(),
+                            fold_background,
+                            fold_corner_radius,
+                            fold_corner_radius * 2.,
+                            layout,
+                            content_origin,
+                            text_bounds,
+                            cx,
+                        );
+                    }
+                });
 
-            for (selection_style, selections) in &layout.selections {
-                for selection in selections {
+                for (range, color) in &layout.highlighted_ranges {
                     self.paint_highlighted_range(
-                        selection.range.clone(),
-                        selection_style.selection,
-                        corner_radius,
-                        corner_radius * 2.,
+                        range.clone(),
+                        *color,
+                        Pixels::ZERO,
+                        line_end_overshoot,
                         layout,
                         content_origin,
-                        scroll_top,
-                        scroll_left,
-                        bounds,
+                        text_bounds,
                         cx,
                     );
+                }
 
-                    if selection.is_local && !selection.range.is_empty() {
-                        invisible_display_ranges.push(selection.range.clone());
-                    }
+                let mut cursors = SmallVec::<[Cursor; 32]>::new();
+                let corner_radius = 0.15 * layout.position_map.line_height;
+                let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
+
+                for (selection_style, selections) in &layout.selections {
+                    for selection in selections {
+                        self.paint_highlighted_range(
+                            selection.range.clone(),
+                            selection_style.selection,
+                            corner_radius,
+                            corner_radius * 2.,
+                            layout,
+                            content_origin,
+                            text_bounds,
+                            cx,
+                        );
 
-                    if !selection.is_local || editor.show_local_cursors(cx) {
-                        let cursor_position = selection.head;
-                        if layout
-                            .visible_display_row_range
-                            .contains(&cursor_position.row())
-                        {
-                            let cursor_row_layout = &layout.position_map.line_layouts
-                                [(cursor_position.row() - start_row) as usize]
-                                .line;
-                            let cursor_column = cursor_position.column() as usize;
-
-                            let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
-                            let mut block_width = cursor_row_layout.x_for_index(cursor_column + 1)
-                                - cursor_character_x;
-                            if block_width == Pixels::ZERO {
-                                block_width = layout.position_map.em_width;
-                            }
-                            let block_text = if let CursorShape::Block = selection.cursor_shape {
-                                layout
-                                    .position_map
-                                    .snapshot
-                                    .chars_at(cursor_position)
-                                    .next()
-                                    .and_then(|(character, _)| {
-                                        let text = character.to_string();
-                                        cx.text_system()
-                                            .layout_text(
-                                                &text,
-                                                cursor_row_layout.font_size,
-                                                &[TextRun {
-                                                    len: text.len(),
-                                                    font: self.style.text.font(),
-                                                    color: self.style.background,
-                                                    underline: None,
-                                                }],
-                                                None,
-                                            )
-                                            .unwrap()
-                                            .pop()
-                                    })
-                            } else {
-                                None
-                            };
-
-                            let x = cursor_character_x - scroll_left;
-                            let y = cursor_position.row() as f32 * layout.position_map.line_height
-                                - scroll_top;
-                            if selection.is_newest {
-                                editor.pixel_position_of_newest_cursor = Some(point(
-                                    bounds.origin.x + x + block_width / 2.,
-                                    bounds.origin.y + y + layout.position_map.line_height / 2.,
-                                ));
+                        if selection.is_local && !selection.range.is_empty() {
+                            invisible_display_ranges.push(selection.range.clone());
+                        }
+
+                        if !selection.is_local || editor.show_local_cursors(cx) {
+                            let cursor_position = selection.head;
+                            if layout
+                                .visible_display_row_range
+                                .contains(&cursor_position.row())
+                            {
+                                let cursor_row_layout = &layout.position_map.line_layouts
+                                    [(cursor_position.row() - start_row) as usize]
+                                    .line;
+                                let cursor_column = cursor_position.column() as usize;
+
+                                let cursor_character_x =
+                                    cursor_row_layout.x_for_index(cursor_column);
+                                let mut block_width = cursor_row_layout
+                                    .x_for_index(cursor_column + 1)
+                                    - cursor_character_x;
+                                if block_width == Pixels::ZERO {
+                                    block_width = layout.position_map.em_width;
+                                }
+                                let block_text = if let CursorShape::Block = selection.cursor_shape
+                                {
+                                    layout
+                                        .position_map
+                                        .snapshot
+                                        .chars_at(cursor_position)
+                                        .next()
+                                        .and_then(|(character, _)| {
+                                            let text = character.to_string();
+                                            cx.text_system()
+                                                .layout_text(
+                                                    &text,
+                                                    cursor_row_layout.font_size,
+                                                    &[TextRun {
+                                                        len: text.len(),
+                                                        font: self.style.text.font(),
+                                                        color: self.style.background,
+                                                        underline: None,
+                                                    }],
+                                                    None,
+                                                )
+                                                .unwrap()
+                                                .pop()
+                                        })
+                                } else {
+                                    None
+                                };
+
+                                let x = cursor_character_x - layout.position_map.scroll_position.x;
+                                let y = cursor_position.row() as f32
+                                    * layout.position_map.line_height
+                                    - layout.position_map.scroll_position.y;
+                                if selection.is_newest {
+                                    editor.pixel_position_of_newest_cursor = Some(point(
+                                        text_bounds.origin.x + x + block_width / 2.,
+                                        text_bounds.origin.y
+                                            + y
+                                            + layout.position_map.line_height / 2.,
+                                    ));
+                                }
+                                cursors.push(Cursor {
+                                    color: selection_style.cursor,
+                                    block_width,
+                                    origin: point(x, y),
+                                    line_height: layout.position_map.line_height,
+                                    shape: selection.cursor_shape,
+                                    block_text,
+                                });
                             }
-                            cursors.push(Cursor {
-                                color: selection_style.cursor,
-                                block_width,
-                                origin: point(x, y),
-                                line_height: layout.position_map.line_height,
-                                shape: selection.cursor_shape,
-                                block_text,
-                            });
                         }
                     }
                 }
-            }
 
-            for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
-                let row = start_row + ix as u32;
-                line_with_invisibles.draw(
-                    layout,
-                    row,
-                    scroll_top,
-                    content_origin,
-                    scroll_left,
-                    whitespace_setting,
-                    &invisible_display_ranges,
-                    cx,
-                )
-            }
-
-            cx.with_z_index(0, |cx| {
-                for cursor in cursors {
-                    cursor.paint(content_origin, cx);
+                for (ix, line_with_invisibles) in
+                    layout.position_map.line_layouts.iter().enumerate()
+                {
+                    let row = start_row + ix as u32;
+                    line_with_invisibles.draw(
+                        layout,
+                        row,
+                        content_origin,
+                        whitespace_setting,
+                        &invisible_display_ranges,
+                        cx,
+                    )
                 }
-            });
 
-            if let Some((position, context_menu)) = layout.context_menu.as_mut() {
-                cx.with_z_index(1, |cx| {
-                    let line_height = self.style.text.line_height_in_pixels(cx.rem_size());
-                    let available_space = size(
-                        AvailableSpace::MinContent,
-                        AvailableSpace::Definite(
-                            (12. * line_height).min((bounds.size.height - line_height) / 2.),
-                        ),
-                    );
-                    let context_menu_size = context_menu.measure(available_space, editor, cx);
-
-                    let cursor_row_layout = &layout.position_map.line_layouts
-                        [(position.row() - start_row) as usize]
-                        .line;
-                    let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
-                    let y =
-                        (position.row() + 1) as f32 * layout.position_map.line_height - scroll_top;
-                    let mut list_origin = content_origin + point(x, y);
-                    let list_width = context_menu_size.width;
-                    let list_height = context_menu_size.height;
-
-                    // Snap the right edge of the list to the right edge of the window if
-                    // its horizontal bounds overflow.
-                    if list_origin.x + list_width > cx.viewport_size().width {
-                        list_origin.x = (cx.viewport_size().width - list_width).max(Pixels::ZERO);
+                cx.with_z_index(0, |cx| {
+                    for cursor in cursors {
+                        cursor.paint(content_origin, cx);
                     }
+                });
 
-                    if list_origin.y + list_height > bounds.lower_right().y {
-                        list_origin.y -= layout.position_map.line_height - list_height;
-                    }
+                if let Some((position, context_menu)) = layout.context_menu.as_mut() {
+                    cx.with_z_index(1, |cx| {
+                        let line_height = self.style.text.line_height_in_pixels(cx.rem_size());
+                        let available_space = size(
+                            AvailableSpace::MinContent,
+                            AvailableSpace::Definite(
+                                (12. * line_height)
+                                    .min((text_bounds.size.height - line_height) / 2.),
+                            ),
+                        );
+                        let context_menu_size = context_menu.measure(available_space, editor, cx);
+
+                        let cursor_row_layout = &layout.position_map.line_layouts
+                            [(position.row() - start_row) as usize]
+                            .line;
+                        let x = cursor_row_layout.x_for_index(position.column() as usize)
+                            - layout.position_map.scroll_position.x;
+                        let y = (position.row() + 1) as f32 * layout.position_map.line_height
+                            - layout.position_map.scroll_position.y;
+                        let mut list_origin = content_origin + point(x, y);
+                        let list_width = context_menu_size.width;
+                        let list_height = context_menu_size.height;
+
+                        // Snap the right edge of the list to the right edge of the window if
+                        // its horizontal bounds overflow.
+                        if list_origin.x + list_width > cx.viewport_size().width {
+                            list_origin.x =
+                                (cx.viewport_size().width - list_width).max(Pixels::ZERO);
+                        }
 
-                    context_menu.draw(list_origin, available_space, editor, cx);
-                })
-            }
+                        if list_origin.y + list_height > text_bounds.lower_right().y {
+                            list_origin.y -= layout.position_map.line_height - list_height;
+                        }
 
-            // if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
-            //     cx.scene().push_stacking_context(None, None);
-
-            //     // This is safe because we check on layout whether the required row is available
-            //     let hovered_row_layout =
-            //         &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
-
-            //     // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
-            //     // height. This is the size we will use to decide whether to render popovers above or below
-            //     // the hovered line.
-            //     let first_size = hover_popovers[0].size();
-            //     let height_to_reserve = first_size.y
-            //         + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.position_map.line_height;
-
-            //     // Compute Hovered Point
-            //     let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
-            //     let y = position.row() as f32 * layout.position_map.line_height - scroll_top;
-            //     let hovered_point = content_origin + point(x, y);
-
-            //     if hovered_point.y - height_to_reserve > 0.0 {
-            //         // There is enough space above. Render popovers above the hovered point
-            //         let mut current_y = hovered_point.y;
-            //         for hover_popover in hover_popovers {
-            //             let size = hover_popover.size();
-            //             let mut popover_origin = point(hovered_point.x, current_y - size.y);
-
-            //             let x_out_of_bounds = bounds.max_x - (popover_origin.x + size.x);
-            //             if x_out_of_bounds < 0.0 {
-            //                 popover_origin.set_x(popover_origin.x + x_out_of_bounds);
-            //             }
-
-            //             hover_popover.paint(
-            //                 popover_origin,
-            //                 Bounds::<Pixels>::from_points(
-            //                     gpui::Point::<Pixels>::zero(),
-            //                     point(f32::MAX, f32::MAX),
-            //                 ), // Let content bleed outside of editor
-            //                 editor,
-            //                 cx,
-            //             );
-
-            //             current_y = popover_origin.y - HOVER_POPOVER_GAP;
-            //         }
-            //     } else {
-            //         // There is not enough space above. Render popovers below the hovered point
-            //         let mut current_y = hovered_point.y + layout.position_map.line_height;
-            //         for hover_popover in hover_popovers {
-            //             let size = hover_popover.size();
-            //             let mut popover_origin = point(hovered_point.x, current_y);
-
-            //             let x_out_of_bounds = bounds.max_x - (popover_origin.x + size.x);
-            //             if x_out_of_bounds < 0.0 {
-            //                 popover_origin.set_x(popover_origin.x + x_out_of_bounds);
-            //             }
-
-            //             hover_popover.paint(
-            //                 popover_origin,
-            //                 Bounds::<Pixels>::from_points(
-            //                     gpui::Point::<Pixels>::zero(),
-            //                     point(f32::MAX, f32::MAX),
-            //                 ), // Let content bleed outside of editor
-            //                 editor,
-            //                 cx,
-            //             );
-
-            //             current_y = popover_origin.y + size.y + HOVER_POPOVER_GAP;
-            //         }
-            //     }
-
-            //     cx.scene().pop_stacking_context();
-            // }
-        })
+                        context_menu.draw(list_origin, available_space, editor, cx);
+                    })
+                }
+
+                // if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
+                //     cx.scene().push_stacking_context(None, None);
+
+                //     // This is safe because we check on layout whether the required row is available
+                //     let hovered_row_layout =
+                //         &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
+
+                //     // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
+                //     // height. This is the size we will use to decide whether to render popovers above or below
+                //     // the hovered line.
+                //     let first_size = hover_popovers[0].size();
+                //     let height_to_reserve = first_size.y
+                //         + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.position_map.line_height;
+
+                //     // Compute Hovered Point
+                //     let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
+                //     let y = position.row() as f32 * layout.position_map.line_height - scroll_top;
+                //     let hovered_point = content_origin + point(x, y);
+
+                //     if hovered_point.y - height_to_reserve > 0.0 {
+                //         // There is enough space above. Render popovers above the hovered point
+                //         let mut current_y = hovered_point.y;
+                //         for hover_popover in hover_popovers {
+                //             let size = hover_popover.size();
+                //             let mut popover_origin = point(hovered_point.x, current_y - size.y);
+
+                //             let x_out_of_bounds = bounds.max_x - (popover_origin.x + size.x);
+                //             if x_out_of_bounds < 0.0 {
+                //                 popover_origin.set_x(popover_origin.x + x_out_of_bounds);
+                //             }
+
+                //             hover_popover.paint(
+                //                 popover_origin,
+                //                 Bounds::<Pixels>::from_points(
+                //                     gpui::Point::<Pixels>::zero(),
+                //                     point(f32::MAX, f32::MAX),
+                //                 ), // Let content bleed outside of editor
+                //                 editor,
+                //                 cx,
+                //             );
+
+                //             current_y = popover_origin.y - HOVER_POPOVER_GAP;
+                //         }
+                //     } else {
+                //         // There is not enough space above. Render popovers below the hovered point
+                //         let mut current_y = hovered_point.y + layout.position_map.line_height;
+                //         for hover_popover in hover_popovers {
+                //             let size = hover_popover.size();
+                //             let mut popover_origin = point(hovered_point.x, current_y);
+
+                //             let x_out_of_bounds = bounds.max_x - (popover_origin.x + size.x);
+                //             if x_out_of_bounds < 0.0 {
+                //                 popover_origin.set_x(popover_origin.x + x_out_of_bounds);
+                //             }
+
+                //             hover_popover.paint(
+                //                 popover_origin,
+                //                 Bounds::<Pixels>::from_points(
+                //                     gpui::Point::<Pixels>::zero(),
+                //                     point(f32::MAX, f32::MAX),
+                //                 ), // Let content bleed outside of editor
+                //                 editor,
+                //                 cx,
+                //             );
+
+                //             current_y = popover_origin.y + size.y + HOVER_POPOVER_GAP;
+                //         }
+                //     }
+
+                //     cx.scene().pop_stacking_context();
+                // }
+            },
+        )
     }
 
     fn scrollbar_left(&self, bounds: &Bounds<Pixels>) -> Pixels {
@@ -1130,8 +1164,6 @@ impl EditorElement {
         line_end_overshoot: Pixels,
         layout: &LayoutState,
         content_origin: gpui::Point<Pixels>,
-        scroll_top: Pixels,
-        scroll_left: Pixels,
         bounds: Bounds<Pixels>,
         cx: &mut ViewContext<Editor>,
     ) {
@@ -1150,7 +1182,7 @@ impl EditorElement {
                 corner_radius,
                 start_y: content_origin.y
                     + row_range.start as f32 * layout.position_map.line_height
-                    - scroll_top,
+                    - layout.position_map.scroll_position.y,
                 lines: row_range
                     .into_iter()
                     .map(|row| {
@@ -1160,17 +1192,17 @@ impl EditorElement {
                             start_x: if row == range.start.row() {
                                 content_origin.x
                                     + line_layout.x_for_index(range.start.column() as usize)
-                                    - scroll_left
+                                    - layout.position_map.scroll_position.x
                             } else {
-                                content_origin.x - scroll_left
+                                content_origin.x - layout.position_map.scroll_position.x
                             },
                             end_x: if row == range.end.row() {
                                 content_origin.x
                                     + line_layout.x_for_index(range.end.column() as usize)
-                                    - scroll_left
+                                    - layout.position_map.scroll_position.x
                             } else {
                                 content_origin.x + line_layout.width + line_end_overshoot
-                                    - scroll_left
+                                    - layout.position_map.scroll_position.x
                             },
                         }
                     })
@@ -1564,7 +1596,6 @@ impl EditorElement {
 
         let mut selections: Vec<(PlayerColor, Vec<SelectionLayout>)> = Vec::new();
         let mut active_rows = BTreeMap::new();
-        let mut fold_ranges = Vec::new();
         let is_singleton = editor.is_singleton(cx);
 
         let highlighted_rows = editor.highlighted_rows();
@@ -1574,19 +1605,6 @@ impl EditorElement {
             cx.theme().colors(),
         );
 
-        fold_ranges.extend(
-            snapshot
-                .folds_in_range(start_anchor..end_anchor)
-                .map(|anchor| {
-                    let start = anchor.start.to_point(&snapshot.buffer_snapshot);
-                    (
-                        start.row,
-                        start.to_display_point(&snapshot.display_snapshot)
-                            ..anchor.end.to_display_point(&snapshot),
-                    )
-                }),
-        );
-
         let mut newest_selection_head = None;
 
         if editor.show_local_selections {
@@ -1684,36 +1702,17 @@ impl EditorElement {
             ShowScrollbar::Auto => {
                 // Git
                 (is_singleton && scrollbar_settings.git_diff && snapshot.buffer_snapshot.has_git_diffs())
-                        ||
-                        // Selections
-                        (is_singleton && scrollbar_settings.selections && !highlighted_ranges.is_empty())
-                        // Scrollmanager
-                        || editor.scroll_manager.scrollbars_visible()
+                ||
+                // Selections
+                (is_singleton && scrollbar_settings.selections && !highlighted_ranges.is_empty())
+                // Scrollmanager
+                || editor.scroll_manager.scrollbars_visible()
             }
             ShowScrollbar::System => editor.scroll_manager.scrollbars_visible(),
             ShowScrollbar::Always => true,
             ShowScrollbar::Never => false,
         };
 
-        let fold_ranges: Vec<(BufferRow, Range<DisplayPoint>, Hsla)> = Vec::new();
-        // todo!()
-
-        // fold_ranges
-        // .into_iter()
-        // .map(|(id, fold)| {
-        //     // todo!("folds!")
-        //     // let color = self
-        //     //     .style
-        //     //     .folds
-        //     //     .ellipses
-        //     //     .background
-        //     //     .style_for(&mut cx.mouse_state::<FoldMarkers>(id as usize))
-        //     //     .color;
-
-        //     // (id, fold, color)
-        // })
-        // .collect();
-
         let head_for_relative = newest_selection_head.unwrap_or_else(|| {
             let newest = editor.selections.newest::<Point>(cx);
             SelectionLayout::new(
@@ -1754,21 +1753,23 @@ impl EditorElement {
             .width;
         let scroll_width = longest_line_width.max(max_visible_line_width) + overscroll.width;
 
-        let (scroll_width, blocks) = self.layout_blocks(
-            start_row..end_row,
-            &snapshot,
-            bounds.size.width,
-            scroll_width,
-            gutter_padding,
-            gutter_width,
-            em_width,
-            gutter_width + gutter_margin,
-            line_height,
-            &style,
-            &line_layouts,
-            editor,
-            cx,
-        );
+        let (scroll_width, blocks) = cx.with_element_id(Some("editor_blocks"), |cx| {
+            self.layout_blocks(
+                start_row..end_row,
+                &snapshot,
+                bounds.size.width,
+                scroll_width,
+                gutter_padding,
+                gutter_width,
+                em_width,
+                gutter_width + gutter_margin,
+                line_height,
+                &style,
+                &line_layouts,
+                editor,
+                cx,
+            )
+        });
 
         let scroll_max = point(
             f32::from((scroll_width - text_size.width) / em_width).max(0.0),
@@ -1828,15 +1829,16 @@ impl EditorElement {
         // );
         // let mode = editor.mode;
 
-        // todo!("fold_indicators")
-        // let mut fold_indicators = editor.render_fold_indicators(
-        //     fold_statuses,
-        //     &style,
-        //     editor.gutter_hovered,
-        //     line_height,
-        //     gutter_margin,
-        //     cx,
-        // );
+        let mut fold_indicators = cx.with_element_id(Some("gutter_fold_indicators"), |cx| {
+            editor.render_fold_indicators(
+                fold_statuses,
+                &style,
+                editor.gutter_hovered,
+                line_height,
+                gutter_margin,
+                cx,
+            )
+        });
 
         // todo!("context_menu")
         // if let Some((_, context_menu)) = context_menu.as_mut() {
@@ -1853,20 +1855,6 @@ impl EditorElement {
         //     );
         // }
 
-        // todo!("fold indicators")
-        // for fold_indicator in fold_indicators.iter_mut() {
-        //     if let Some(indicator) = fold_indicator.as_mut() {
-        //         indicator.layout(
-        //             SizeConstraint::strict_along(
-        //                 Axis::Vertical,
-        //                 line_height * style.code_actions.vertical_scale,
-        //             ),
-        //             editor,
-        //             cx,
-        //         );
-        //     }
-        // }
-
         // todo!("hover popovers")
         // if let Some((_, hover_popovers)) = hover.as_mut() {
         //     for hover_popover in hover_popovers.iter_mut() {
@@ -1926,6 +1914,10 @@ impl EditorElement {
             mode: editor_mode,
             position_map: Arc::new(PositionMap {
                 size: bounds.size,
+                scroll_position: point(
+                    scroll_position.x * em_width,
+                    scroll_position.y * line_height,
+                ),
                 scroll_max,
                 line_layouts,
                 line_height,
@@ -1933,6 +1925,7 @@ impl EditorElement {
                 em_advance,
                 snapshot,
             }),
+            visible_anchor_range: start_anchor..end_anchor,
             visible_display_row_range: start_row..end_row,
             wrap_guides,
             gutter_size,
@@ -1946,14 +1939,13 @@ impl EditorElement {
             active_rows,
             highlighted_rows,
             highlighted_ranges,
-            fold_ranges,
             line_number_layouts,
             display_hunks,
             blocks,
             selections,
             context_menu,
             code_actions_indicator,
-            // fold_indicators,
+            fold_indicators,
             tab_invisible,
             space_invisible,
             // hover_popovers: hover,
@@ -2019,7 +2011,6 @@ impl EditorElement {
                     })
                 }
                 TransformBlock::ExcerptHeader {
-                    id,
                     buffer,
                     range,
                     starts_new_buffer,
@@ -2041,9 +2032,7 @@ impl EditorElement {
                             .map_or(range.context.start, |primary| primary.start);
                         let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
 
-                        // todo!("avoid ElementId collision risk here")
-                        let icon_button_id: usize = id.clone().into();
-                        IconButton::new(icon_button_id, ui::Icon::ArrowUpRight)
+                        IconButton::new(block_id, ui::Icon::ArrowUpRight)
                             .on_click(move |editor: &mut Editor, cx| {
                                 editor.jump(jump_path.clone(), jump_position, jump_anchor, cx);
                             })
@@ -2137,11 +2126,13 @@ impl EditorElement {
         bounds: Bounds<Pixels>,
         gutter_bounds: Bounds<Pixels>,
         text_bounds: Bounds<Pixels>,
-        position_map: &Arc<PositionMap>,
+        layout: &LayoutState,
         cx: &mut ViewContext<Editor>,
     ) {
+        let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
+
         cx.on_mouse_event({
-            let position_map = position_map.clone();
+            let position_map = layout.position_map.clone();
             move |editor, event: &ScrollWheelEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
@@ -2153,7 +2144,7 @@ impl EditorElement {
             }
         });
         cx.on_mouse_event({
-            let position_map = position_map.clone();
+            let position_map = layout.position_map.clone();
             move |editor, event: &MouseDownEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
@@ -2165,7 +2156,7 @@ impl EditorElement {
             }
         });
         cx.on_mouse_event({
-            let position_map = position_map.clone();
+            let position_map = layout.position_map.clone();
             move |editor, event: &MouseUpEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
@@ -2178,7 +2169,7 @@ impl EditorElement {
         });
         // todo!()
         // on_down(MouseButton::Right, {
-        //     let position_map = position_map.clone();
+        //     let position_map = layout.position_map.clone();
         //     move |event, editor, cx| {
         //         if !Self::mouse_right_down(
         //             editor,
@@ -2192,7 +2183,7 @@ impl EditorElement {
         //     }
         // });
         cx.on_mouse_event({
-            let position_map = position_map.clone();
+            let position_map = layout.position_map.clone();
             move |editor, event: &MouseMoveEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
@@ -2322,18 +2313,16 @@ impl LineWithInvisibles {
         &self,
         layout: &LayoutState,
         row: u32,
-        scroll_top: Pixels,
         content_origin: gpui::Point<Pixels>,
-        scroll_left: Pixels,
         whitespace_setting: ShowWhitespaceSetting,
         selection_ranges: &[Range<DisplayPoint>],
         cx: &mut ViewContext<Editor>,
     ) {
         let line_height = layout.position_map.line_height;
-        let line_y = line_height * row as f32 - scroll_top;
+        let line_y = line_height * row as f32 - layout.position_map.scroll_position.y;
 
         self.line.paint(
-            content_origin + gpui::point(-scroll_left, line_y),
+            content_origin + gpui::point(-layout.position_map.scroll_position.x, line_y),
             line_height,
             cx,
         );

crates/editor2/src/git.rs 🔗

@@ -60,8 +60,8 @@ pub fn diff_hunk_to_display(hunk: DiffHunk<u32>, snapshot: &DisplaySnapshot) ->
     let folds_end = Point::new(hunk.buffer_range.end + 2, 0);
     let folds_range = folds_start..folds_end;
 
-    let containing_fold = snapshot.folds_in_range(folds_range).find(|fold_range| {
-        let fold_point_range = fold_range.to_point(&snapshot.buffer_snapshot);
+    let containing_fold = snapshot.folds_in_range(folds_range).find(|fold| {
+        let fold_point_range = fold.range.to_point(&snapshot.buffer_snapshot);
         let fold_point_range = fold_point_range.start..=fold_point_range.end;
 
         let folded_start = fold_point_range.contains(&hunk_start_point);
@@ -72,7 +72,7 @@ pub fn diff_hunk_to_display(hunk: DiffHunk<u32>, snapshot: &DisplaySnapshot) ->
     });
 
     if let Some(fold) = containing_fold {
-        let row = fold.start.to_display_point(snapshot).row();
+        let row = fold.range.start.to_display_point(snapshot).row();
         DisplayDiffHunk::Folded { display_row: row }
     } else {
         let start = hunk_start_point.to_display_point(snapshot).row();

crates/gpui2/src/element.rs 🔗

@@ -3,7 +3,7 @@ use crate::{
 };
 use derive_more::{Deref, DerefMut};
 pub(crate) use smallvec::SmallVec;
-use std::{any::Any, mem};
+use std::{any::Any, fmt::Debug, mem};
 
 pub trait Element<V: 'static> {
     type ElementState: 'static;
@@ -33,6 +33,42 @@ pub trait Element<V: 'static> {
         element_state: &mut Self::ElementState,
         cx: &mut ViewContext<V>,
     );
+
+    fn draw<T, R>(
+        self,
+        origin: Point<Pixels>,
+        available_space: Size<T>,
+        view_state: &mut V,
+        cx: &mut ViewContext<V>,
+        f: impl FnOnce(&Self::ElementState, &mut ViewContext<V>) -> R,
+    ) -> R
+    where
+        Self: Sized,
+        T: Clone + Default + Debug + Into<AvailableSpace>,
+    {
+        let mut element = RenderedElement {
+            element: self,
+            phase: ElementRenderPhase::Start,
+        };
+        element.draw(origin, available_space.map(Into::into), view_state, cx);
+        if let ElementRenderPhase::Painted { frame_state } = &element.phase {
+            if let Some(frame_state) = frame_state.as_ref() {
+                f(&frame_state, cx)
+            } else {
+                let element_id = element
+                    .element
+                    .element_id()
+                    .expect("we either have some frame_state or some element_id");
+                cx.with_element_state(element_id, |element_state, cx| {
+                    let element_state = element_state.unwrap();
+                    let result = f(&element_state, cx);
+                    (result, element_state)
+                })
+            }
+        } else {
+            unreachable!()
+        }
+    }
 }
 
 #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
@@ -99,7 +135,9 @@ enum ElementRenderPhase<V> {
         available_space: Size<AvailableSpace>,
         frame_state: Option<V>,
     },
-    Painted,
+    Painted {
+        frame_state: Option<V>,
+    },
 }
 
 /// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
@@ -157,7 +195,7 @@ where
             ElementRenderPhase::Start => panic!("must call initialize before layout"),
             ElementRenderPhase::LayoutRequested { .. }
             | ElementRenderPhase::LayoutComputed { .. }
-            | ElementRenderPhase::Painted => {
+            | ElementRenderPhase::Painted { .. } => {
                 panic!("element rendered twice")
             }
         };
@@ -192,7 +230,7 @@ where
                     self.element
                         .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
                 }
-                ElementRenderPhase::Painted
+                ElementRenderPhase::Painted { frame_state }
             }
 
             _ => panic!("must call layout before paint"),

crates/gpui2/src/elements/div.rs 🔗

@@ -6,15 +6,15 @@ use crate::{
     SharedString, Size, Style, StyleRefinement, Styled, Task, View, ViewContext, Visibility,
 };
 use collections::HashMap;
-use parking_lot::Mutex;
 use refineable::Refineable;
 use smallvec::SmallVec;
 use std::{
     any::{Any, TypeId},
+    cell::RefCell,
     fmt::Debug,
     marker::PhantomData,
     mem,
-    sync::Arc,
+    rc::Rc,
     time::Duration,
 };
 use taffy::style::Overflow;
@@ -420,7 +420,7 @@ pub trait StatefulInteractiveComponent<V: 'static, E: Element<V>>: InteractiveCo
             self.interactivity().tooltip_builder.is_none(),
             "calling tooltip more than once on the same element is not supported"
         );
-        self.interactivity().tooltip_builder = Some(Arc::new(move |view_state, cx| {
+        self.interactivity().tooltip_builder = Some(Rc::new(move |view_state, cx| {
             build_tooltip(view_state, cx).into()
         }));
 
@@ -569,7 +569,7 @@ type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
 
 pub type HoverListener<V> = Box<dyn Fn(&mut V, bool, &mut ViewContext<V>) + 'static>;
 
-pub type TooltipBuilder<V> = Arc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>;
+pub type TooltipBuilder<V> = Rc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>;
 
 pub type KeyDownListener<V> =
     Box<dyn Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
@@ -725,6 +725,12 @@ pub struct DivState {
     interactive_state: InteractiveElementState,
 }
 
+impl DivState {
+    pub fn is_active(&self) -> bool {
+        self.interactive_state.pending_mouse_down.borrow().is_some()
+    }
+}
+
 pub struct Interactivity<V> {
     pub element_id: Option<ElementId>,
     pub key_context: KeyContext,
@@ -890,7 +896,7 @@ where
 
         if !click_listeners.is_empty() || drag_listener.is_some() {
             let pending_mouse_down = element_state.pending_mouse_down.clone();
-            let mouse_down = pending_mouse_down.lock().clone();
+            let mouse_down = pending_mouse_down.borrow().clone();
             if let Some(mouse_down) = mouse_down {
                 if let Some(drag_listener) = drag_listener {
                     let active_state = element_state.clicked_state.clone();
@@ -904,7 +910,7 @@ where
                             && bounds.contains_point(&event.position)
                             && (event.position - mouse_down.position).magnitude() > DRAG_THRESHOLD
                         {
-                            *active_state.lock() = ElementClickedState::default();
+                            *active_state.borrow_mut() = ElementClickedState::default();
                             let cursor_offset = event.position - bounds.origin;
                             let drag = drag_listener(view_state, cursor_offset, cx);
                             cx.active_drag = Some(drag);
@@ -924,13 +930,13 @@ where
                             listener(view_state, &mouse_click, cx);
                         }
                     }
-                    *pending_mouse_down.lock() = None;
+                    *pending_mouse_down.borrow_mut() = None;
                     cx.notify();
                 });
             } else {
                 cx.on_mouse_event(move |_view_state, event: &MouseDownEvent, phase, cx| {
                     if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                        *pending_mouse_down.lock() = Some(event.clone());
+                        *pending_mouse_down.borrow_mut() = Some(event.clone());
                         cx.notify();
                     }
                 });
@@ -946,8 +952,8 @@ where
                     return;
                 }
                 let is_hovered =
-                    bounds.contains_point(&event.position) && has_mouse_down.lock().is_none();
-                let mut was_hovered = was_hovered.lock();
+                    bounds.contains_point(&event.position) && has_mouse_down.borrow().is_none();
+                let mut was_hovered = was_hovered.borrow_mut();
 
                 if is_hovered != was_hovered.clone() {
                     *was_hovered = is_hovered;
@@ -968,13 +974,13 @@ where
                 }
 
                 let is_hovered =
-                    bounds.contains_point(&event.position) && pending_mouse_down.lock().is_none();
+                    bounds.contains_point(&event.position) && pending_mouse_down.borrow().is_none();
                 if !is_hovered {
-                    active_tooltip.lock().take();
+                    active_tooltip.borrow_mut().take();
                     return;
                 }
 
-                if active_tooltip.lock().is_none() {
+                if active_tooltip.borrow().is_none() {
                     let task = cx.spawn({
                         let active_tooltip = active_tooltip.clone();
                         let tooltip_builder = tooltip_builder.clone();
@@ -982,7 +988,7 @@ where
                         move |view, mut cx| async move {
                             cx.background_executor().timer(TOOLTIP_DELAY).await;
                             view.update(&mut cx, move |view_state, cx| {
-                                active_tooltip.lock().replace(ActiveTooltip {
+                                active_tooltip.borrow_mut().replace(ActiveTooltip {
                                     waiting: None,
                                     tooltip: Some(AnyTooltip {
                                         view: tooltip_builder(view_state, cx),
@@ -994,14 +1000,14 @@ where
                             .ok();
                         }
                     });
-                    active_tooltip.lock().replace(ActiveTooltip {
+                    active_tooltip.borrow_mut().replace(ActiveTooltip {
                         waiting: Some(task),
                         tooltip: None,
                     });
                 }
             });
 
-            if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() {
+            if let Some(active_tooltip) = element_state.active_tooltip.borrow().as_ref() {
                 if active_tooltip.tooltip.is_some() {
                     cx.active_tooltip = active_tooltip.tooltip.clone()
                 }
@@ -1009,10 +1015,10 @@ where
         }
 
         let active_state = element_state.clicked_state.clone();
-        if !active_state.lock().is_clicked() {
+        if !active_state.borrow().is_clicked() {
             cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
                 if phase == DispatchPhase::Capture {
-                    *active_state.lock() = ElementClickedState::default();
+                    *active_state.borrow_mut() = ElementClickedState::default();
                     cx.notify();
                 }
             });
@@ -1027,7 +1033,7 @@ where
                         .map_or(false, |bounds| bounds.contains_point(&down.position));
                     let element = bounds.contains_point(&down.position);
                     if group || element {
-                        *active_state.lock() = ElementClickedState { group, element };
+                        *active_state.borrow_mut() = ElementClickedState { group, element };
                         cx.notify();
                     }
                 }
@@ -1038,14 +1044,14 @@ where
         if overflow.x == Overflow::Scroll || overflow.y == Overflow::Scroll {
             let scroll_offset = element_state
                 .scroll_offset
-                .get_or_insert_with(Arc::default)
+                .get_or_insert_with(Rc::default)
                 .clone();
             let line_height = cx.line_height();
             let scroll_max = (content_size - bounds.size).max(&Size::default());
 
             cx.on_mouse_event(move |_, event: &ScrollWheelEvent, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    let mut scroll_offset = scroll_offset.lock();
+                    let mut scroll_offset = scroll_offset.borrow_mut();
                     let old_scroll_offset = *scroll_offset;
                     let delta = event.delta.pixel_delta(line_height);
 
@@ -1074,7 +1080,7 @@ where
         let scroll_offset = element_state
             .scroll_offset
             .as_ref()
-            .map(|scroll_offset| *scroll_offset.lock());
+            .map(|scroll_offset| *scroll_offset.borrow());
 
         cx.with_key_dispatch(
             self.key_context.clone(),
@@ -1173,7 +1179,7 @@ where
             }
         }
 
-        let clicked_state = element_state.clicked_state.lock();
+        let clicked_state = element_state.clicked_state.borrow();
         if clicked_state.group {
             if let Some(group) = self.group_active_style.as_ref() {
                 style.refine(&group.style)
@@ -1227,11 +1233,11 @@ impl<V: 'static> Default for Interactivity<V> {
 #[derive(Default)]
 pub struct InteractiveElementState {
     pub focus_handle: Option<FocusHandle>,
-    pub clicked_state: Arc<Mutex<ElementClickedState>>,
-    pub hover_state: Arc<Mutex<bool>>,
-    pub pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
-    pub scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
-    pub active_tooltip: Arc<Mutex<Option<ActiveTooltip>>>,
+    pub clicked_state: Rc<RefCell<ElementClickedState>>,
+    pub hover_state: Rc<RefCell<bool>>,
+    pub pending_mouse_down: Rc<RefCell<Option<MouseDownEvent>>>,
+    pub scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
+    pub active_tooltip: Rc<RefCell<Option<ActiveTooltip>>>,
 }
 
 pub struct ActiveTooltip {

crates/gpui2/src/elements/uniform_list.rs 🔗

@@ -3,9 +3,8 @@ use crate::{
     ElementId, InteractiveComponent, InteractiveElementState, Interactivity, LayoutId, Pixels,
     Point, Size, StyleRefinement, Styled, ViewContext,
 };
-use parking_lot::Mutex;
 use smallvec::SmallVec;
-use std::{cmp, mem, ops::Range, sync::Arc};
+use std::{cell::RefCell, cmp, mem, ops::Range, rc::Rc};
 use taffy::style::Overflow;
 
 /// uniform_list provides lazy rendering for a set of items that are of uniform height.
@@ -61,23 +60,23 @@ pub struct UniformList<V: 'static> {
 }
 
 #[derive(Clone, Default)]
-pub struct UniformListScrollHandle(Arc<Mutex<Option<ScrollHandleState>>>);
+pub struct UniformListScrollHandle(Rc<RefCell<Option<ScrollHandleState>>>);
 
 #[derive(Clone, Debug)]
 struct ScrollHandleState {
     item_height: Pixels,
     list_height: Pixels,
-    scroll_offset: Arc<Mutex<Point<Pixels>>>,
+    scroll_offset: Rc<RefCell<Point<Pixels>>>,
 }
 
 impl UniformListScrollHandle {
     pub fn new() -> Self {
-        Self(Arc::new(Mutex::new(None)))
+        Self(Rc::new(RefCell::new(None)))
     }
 
     pub fn scroll_to_item(&self, ix: usize) {
-        if let Some(state) = &*self.0.lock() {
-            let mut scroll_offset = state.scroll_offset.lock();
+        if let Some(state) = &*self.0.borrow() {
+            let mut scroll_offset = state.scroll_offset.borrow_mut();
             let item_top = state.item_height * ix;
             let item_bottom = item_top + state.item_height;
             let scroll_top = -scroll_offset.y;
@@ -196,7 +195,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
         let shared_scroll_offset = element_state
             .interactive
             .scroll_offset
-            .get_or_insert_with(Arc::default)
+            .get_or_insert_with(Rc::default)
             .clone();
 
         interactivity.paint(
@@ -222,7 +221,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
                             .measure_item(view_state, Some(padded_bounds.size.width), cx)
                             .height;
                         if let Some(scroll_handle) = self.scroll_handle.clone() {
-                            scroll_handle.0.lock().replace(ScrollHandleState {
+                            scroll_handle.0.borrow_mut().replace(ScrollHandleState {
                                 item_height,
                                 list_height: padded_bounds.size.height,
                                 scroll_offset: shared_scroll_offset,

crates/gpui2/src/view.rs 🔗

@@ -63,6 +63,16 @@ impl<V: 'static> View<V> {
     pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V {
         self.model.read(cx)
     }
+
+    pub fn render_with<C>(&self, component: C) -> RenderViewWith<C, V>
+    where
+        C: 'static + Component<V>,
+    {
+        RenderViewWith {
+            view: self.clone(),
+            component: Some(component),
+        }
+    }
 }
 
 impl<V> Clone for View<V> {
@@ -281,12 +291,12 @@ where
     }
 }
 
-pub struct RenderView<C, V> {
+pub struct RenderViewWith<C, V> {
     view: View<V>,
     component: Option<C>,
 }
 
-impl<C, ParentViewState, ViewState> Component<ParentViewState> for RenderView<C, ViewState>
+impl<C, ParentViewState, ViewState> Component<ParentViewState> for RenderViewWith<C, ViewState>
 where
     C: 'static + Component<ViewState>,
     ParentViewState: 'static,
@@ -297,7 +307,7 @@ where
     }
 }
 
-impl<C, ParentViewState, ViewState> Element<ParentViewState> for RenderView<C, ViewState>
+impl<C, ParentViewState, ViewState> Element<ParentViewState> for RenderViewWith<C, ViewState>
 where
     C: 'static + Component<ViewState>,
     ParentViewState: 'static,
@@ -348,17 +358,6 @@ where
     }
 }
 
-pub fn render_view<C, V>(view: &View<V>, component: C) -> RenderView<C, V>
-where
-    C: 'static + Component<V>,
-    V: 'static,
-{
-    RenderView {
-        view: view.clone(),
-        component: Some(component),
-    }
-}
-
 mod any_view {
     use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
     use std::any::Any;

crates/gpui2/src/window.rs 🔗

@@ -216,7 +216,7 @@ pub struct Window {
 
 // #[derive(Default)]
 pub(crate) struct Frame {
-    element_states: HashMap<GlobalElementId, AnyBox>,
+    pub(crate) element_states: HashMap<GlobalElementId, AnyBox>,
     mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseListener)>>,
     pub(crate) dispatch_tree: DispatchTree,
     pub(crate) focus_listeners: Vec<AnyFocusListener>,
@@ -2471,7 +2471,7 @@ impl From<SmallVec<[u32; 16]>> for StackingOrder {
 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
 pub enum ElementId {
     View(EntityId),
-    Number(usize),
+    Integer(usize),
     Name(SharedString),
     FocusHandle(FocusId),
 }
@@ -2484,13 +2484,13 @@ impl From<EntityId> for ElementId {
 
 impl From<usize> for ElementId {
     fn from(id: usize) -> Self {
-        ElementId::Number(id)
+        ElementId::Integer(id)
     }
 }
 
 impl From<i32> for ElementId {
     fn from(id: i32) -> Self {
-        Self::Number(id as usize)
+        Self::Integer(id as usize)
     }
 }