diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 2f76d4988cd1266d4434b34d77a9199dbd6671f1..9d1e48be4e7ce51c1da579037433b29a71b0de40 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6806,19 +6806,14 @@ impl View for Editor { }); if font_changed { - let handle = self.handle.clone(); - cx.defer(move |_, cx: &mut ViewContext| { - if let Some(editor) = handle.upgrade(cx) { - editor.update(cx, |editor, cx| { - hide_hover(editor, &HideHover, cx); - hide_link_definition(editor, cx); - }) - } + cx.defer(move |editor, cx: &mut ViewContext| { + hide_hover(editor, &HideHover, cx); + hide_link_definition(editor, cx); }); } Stack::new() - .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed()) + .with_child(EditorElement::new(style.clone()).boxed()) .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed()) .boxed() } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index f3f985720e9215d521315b191fea403bbfaea203..7ef3c3e81d34d000ab76d6e7b24248477ee2c8ea 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -31,8 +31,8 @@ use gpui::{ json::{self, ToJson}, platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent}, text_layout::{self, Line, RunStyle, TextLayoutCache}, - AppContext, Axis, Border, CursorRegion, Drawable, Element, EventContext, MouseRegion, Quad, - SceneBuilder, SizeConstraint, ViewContext, WeakViewHandle, WindowContext, + Axis, Border, CursorRegion, Drawable, Element, EventContext, MouseRegion, Quad, SceneBuilder, + SizeConstraint, ViewContext, WindowContext, }; use itertools::Itertools; use json::json; @@ -44,7 +44,7 @@ use std::{ cmp::{self, Ordering}, fmt::Write, iter, - ops::{DerefMut, Range}, + ops::Range, sync::Arc, }; use workspace::item::Item; @@ -86,140 +86,128 @@ impl SelectionLayout { #[derive(Clone)] pub struct EditorElement { - view: WeakViewHandle, style: Arc, } impl EditorElement { - pub fn new(view: WeakViewHandle, style: EditorStyle) -> Self { + pub fn new(style: EditorStyle) -> Self { Self { - view, style: Arc::new(style), } } - fn update_view(&self, cx: &mut AppContext, f: F) -> T - where - F: FnOnce(&mut Editor, &mut ViewContext) -> T, - { - self.view.upgrade(cx).unwrap().update(cx, f) - } - - fn snapshot(&self, cx: &mut AppContext) -> EditorSnapshot { - self.update_view(cx, |view, cx| view.snapshot(cx)) - } - fn attach_mouse_handlers( scene: &mut SceneBuilder, - view: &WeakViewHandle, position_map: &Arc, has_popovers: bool, visible_bounds: RectF, text_bounds: RectF, gutter_bounds: RectF, bounds: RectF, + cx: &mut ViewContext, ) { enum EditorElementMouseHandlers {} scene.push_mouse_region( - MouseRegion::new::(view.id(), view.id(), visible_bounds) - .on_down(MouseButton::Left, { - let position_map = position_map.clone(); - move |e, _, cx| { - if !Self::mouse_down( - e.platform_event, - position_map.as_ref(), - text_bounds, - gutter_bounds, - cx, - ) { - cx.propagate_event(); - } - } - }) - .on_down(MouseButton::Right, { - let position_map = position_map.clone(); - move |e, _, cx| { - if !Self::mouse_right_down( - e.position, - position_map.as_ref(), - text_bounds, - cx, - ) { - cx.propagate_event(); - } + MouseRegion::new::( + cx.view_id(), + cx.view_id(), + visible_bounds, + ) + .on_down(MouseButton::Left, { + let position_map = position_map.clone(); + move |e, _, cx| { + if !Self::mouse_down( + e.platform_event, + position_map.as_ref(), + text_bounds, + gutter_bounds, + cx, + ) { + cx.propagate_event(); } - }) - .on_up(MouseButton::Left, { - let view = view.clone(); - let position_map = position_map.clone(); - move |e, _, cx| { - if !Self::mouse_up( - view.clone(), - e.position, - e.cmd, - e.shift, - position_map.as_ref(), - text_bounds, - cx, - ) { - cx.propagate_event() - } + } + }) + .on_down(MouseButton::Right, { + let position_map = position_map.clone(); + move |event, _, cx| { + if !Self::mouse_right_down( + event.position, + position_map.as_ref(), + text_bounds, + cx, + ) { + cx.propagate_event(); } - }) - .on_drag(MouseButton::Left, { - let view = view.clone(); - let position_map = position_map.clone(); - move |e, _, cx| { - if !Self::mouse_dragged( - view.clone(), - e.platform_event, - position_map.as_ref(), - text_bounds, - cx, - ) { - cx.propagate_event() - } + } + }) + .on_up(MouseButton::Left, { + let position_map = position_map.clone(); + move |event, editor, cx| { + if !Self::mouse_up( + event.position, + event.cmd, + event.shift, + position_map.as_ref(), + text_bounds, + editor, + cx, + ) { + cx.propagate_event() } - }) - .on_move({ - let position_map = position_map.clone(); - move |e, _, cx| { - if !Self::mouse_moved(e.platform_event, &position_map, text_bounds, cx) { - cx.propagate_event() - } + } + }) + .on_drag(MouseButton::Left, { + let position_map = position_map.clone(); + move |event, editor, cx| { + if !Self::mouse_dragged( + event.platform_event, + position_map.as_ref(), + text_bounds, + editor, + cx, + ) { + cx.propagate_event() } - }) - .on_move_out(move |_, _: &mut Editor, cx| { - if has_popovers { - cx.dispatch_action(HideHover); + } + }) + .on_move({ + let position_map = position_map.clone(); + move |e, _, cx| { + if !Self::mouse_moved(e.platform_event, &position_map, text_bounds, cx) { + cx.propagate_event() } - }) - .on_scroll({ - let position_map = position_map.clone(); - move |e, _, cx| { - if !Self::scroll( - e.position, - *e.delta.raw(), - e.delta.precise(), - &position_map, - bounds, - cx, - ) { - cx.propagate_event() - } + } + }) + .on_move_out(move |_, _: &mut Editor, cx| { + if has_popovers { + cx.dispatch_action(HideHover); + } + }) + .on_scroll({ + let position_map = position_map.clone(); + move |e, _, cx| { + if !Self::scroll( + e.position, + *e.delta.raw(), + e.delta.precise(), + &position_map, + bounds, + cx, + ) { + cx.propagate_event() } - }), + } + }), ); enum GutterHandlers {} scene.push_mouse_region( - MouseRegion::new::(view.id(), view.id() + 1, gutter_bounds).on_hover( - |hover, _: &mut Editor, cx| { + MouseRegion::new::(cx.view_id(), cx.view_id() + 1, gutter_bounds) + .on_hover(|hover, _: &mut Editor, cx| { cx.dispatch_action(GutterHover { hovered: hover.started, }) - }, - ), + }), ) } @@ -288,17 +276,16 @@ impl EditorElement { } fn mouse_up( - view: WeakViewHandle, position: Vector2F, cmd: bool, shift: bool, position_map: &PositionMap, text_bounds: RectF, + editor: &mut Editor, cx: &mut EventContext, ) -> bool { - let view = view.upgrade(cx).unwrap().read(cx); - let end_selection = view.has_pending_selection(); - let pending_nonempty_selections = view.has_pending_nonempty_selection(); + let end_selection = editor.has_pending_selection(); + let pending_nonempty_selections = editor.has_pending_nonempty_selection(); if end_selection { cx.dispatch_action(Select(SelectPhase::End)); @@ -322,7 +309,6 @@ impl EditorElement { } fn mouse_dragged( - view: WeakViewHandle, MouseMovedEvent { modifiers: Modifiers { cmd, shift, .. }, position, @@ -330,6 +316,7 @@ impl EditorElement { }: MouseMovedEvent, position_map: &PositionMap, text_bounds: RectF, + editor: &mut Editor, cx: &mut EventContext, ) -> bool { // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed @@ -351,8 +338,7 @@ impl EditorElement { shift_held: shift, }); - let view = view.upgrade(cx).unwrap().read(cx); - if view.has_pending_selection() { + if editor.has_pending_selection() { let mut scroll_delta = Vector2F::zero(); let vertical_margin = position_map.line_height.min(text_bounds.height() / 3.0); @@ -758,7 +744,7 @@ impl EditorElement { .row; scene.push_mouse_region( - MouseRegion::new::(self.view.id(), *id as usize, bound) + MouseRegion::new::(cx.view_id(), *id as usize, bound) .on_click(MouseButton::Left, move |_, _: &mut Editor, cx| { cx.dispatch_action(UnfoldAt { buffer_row }) }) @@ -1003,7 +989,6 @@ impl EditorElement { return; } - let view = self.view.clone(); let style = &self.style.theme.scrollbar; let top = bounds.min_y(); @@ -1052,58 +1037,37 @@ impl EditorElement { style: CursorStyle::Arrow, }); scene.push_mouse_region( - MouseRegion::new::(view.id(), view.id(), track_bounds) - .on_move({ - let view = view.clone(); - move |_, _: &mut Editor, cx| { - if let Some(view) = view.upgrade(cx.deref_mut()) { - view.update(cx.deref_mut(), |view, cx| { - view.scroll_manager.show_scrollbar(cx); - }); - } - } + MouseRegion::new::(cx.view_id(), cx.view_id(), track_bounds) + .on_move(move |_, editor: &mut Editor, cx| { + editor.scroll_manager.show_scrollbar(cx); }) .on_down(MouseButton::Left, { - let view = view.clone(); let row_range = row_range.clone(); - move |e, _: &mut Editor, cx| { - let y = e.position.y(); - if let Some(view) = view.upgrade(cx.deref_mut()) { - view.update(cx.deref_mut(), |view, cx| { - if y < thumb_top || thumb_bottom < y { - let center_row = - ((y - top) * max_row as f32 / height).round() as u32; - let top_row = center_row.saturating_sub( - (row_range.end - row_range.start) as u32 / 2, - ); - let mut position = view.scroll_position(cx); - position.set_y(top_row as f32); - view.set_scroll_position(position, cx); - } else { - view.scroll_manager.show_scrollbar(cx); - } - }); + move |event, editor: &mut Editor, cx| { + let y = event.position.y(); + if y < thumb_top || thumb_bottom < y { + let center_row = ((y - top) * max_row as f32 / height).round() as u32; + let top_row = center_row + .saturating_sub((row_range.end - row_range.start) as u32 / 2); + let mut position = editor.scroll_position(cx); + position.set_y(top_row as f32); + editor.set_scroll_position(position, cx); + } else { + editor.scroll_manager.show_scrollbar(cx); } } }) .on_drag(MouseButton::Left, { - let view = view.clone(); - move |e, _: &mut Editor, cx| { - let y = e.prev_mouse_position.y(); - let new_y = e.position.y(); + move |event, editor: &mut Editor, cx| { + let y = event.prev_mouse_position.y(); + let new_y = event.position.y(); if thumb_top < y && y < thumb_bottom { - if let Some(view) = view.upgrade(cx.deref_mut()) { - view.update(cx.deref_mut(), |view, cx| { - let mut position = view.scroll_position(cx); - position.set_y( - position.y() + (new_y - y) * (max_row as f32) / height, - ); - if position.y() < 0.0 { - position.set_y(0.); - } - view.set_scroll_position(position, cx); - }); + let mut position = editor.scroll_position(cx); + position.set_y(position.y() + (new_y - y) * (max_row as f32) / height); + if position.y() < 0.0 { + position.set_y(0.); } + editor.set_scroll_position(position, cx); } } }), @@ -1620,7 +1584,7 @@ impl Drawable for EditorElement { unimplemented!("we don't yet handle an infinite width constraint on buffer elements"); } - let snapshot = self.snapshot(cx); + let snapshot = editor.snapshot(cx); let style = self.style.clone(); let line_height = style.text.line_height(cx.font_cache()); @@ -1641,22 +1605,22 @@ impl Drawable for EditorElement { let em_width = style.text.em_width(cx.font_cache()); let em_advance = style.text.em_advance(cx.font_cache()); let overscroll = vec2f(em_width, 0.); - let snapshot = self.update_view(cx, |view, cx| { - view.set_visible_line_count(size.y() / line_height); + let snapshot = { + editor.set_visible_line_count(size.y() / line_height); let editor_width = text_width - gutter_margin - overscroll.x() - em_width; - let wrap_width = match view.soft_wrap_mode(cx) { + let wrap_width = match editor.soft_wrap_mode(cx) { SoftWrap::None => (MAX_LINE_LEN / 2) as f32 * em_advance, SoftWrap::EditorWidth => editor_width, SoftWrap::Column(column) => editor_width.min(column as f32 * em_advance), }; - if view.set_wrap_width(Some(wrap_width), cx) { - view.snapshot(cx) + if editor.set_wrap_width(Some(wrap_width), cx) { + editor.snapshot(cx) } else { snapshot } - }); + }; let scroll_height = (snapshot.max_point().row() + 1) as f32 * line_height; if let EditorMode::AutoHeight { max_lines } = snapshot.mode { @@ -1678,11 +1642,8 @@ impl Drawable for EditorElement { let gutter_size = vec2f(gutter_width, size.y()); let text_size = vec2f(text_width, size.y()); - let (autoscroll_horizontally, mut snapshot) = self.update_view(cx, |view, cx| { - let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, cx); - let snapshot = view.snapshot(cx); - (autoscroll_horizontally, snapshot) - }); + let autoscroll_horizontally = editor.autoscroll_vertically(size.y(), line_height, cx); + let mut snapshot = editor.snapshot(cx); let scroll_position = snapshot.scroll_position(); // The scroll position is a fractional point, the whole number of which represents @@ -1714,102 +1675,95 @@ impl Drawable for EditorElement { let mut selections: Vec<(ReplicaId, Vec)> = Vec::new(); let mut active_rows = BTreeMap::new(); - let mut highlighted_rows = None; - let mut highlighted_ranges = Vec::new(); let mut fold_ranges = Vec::new(); - let mut show_scrollbars = false; - let mut include_root = false; - let mut is_singleton = false; - self.update_view(cx, |view, cx| { - is_singleton = view.is_singleton(cx); - - let display_map = view.display_map.update(cx, |map, cx| map.snapshot(cx)); + let is_singleton = editor.is_singleton(cx); + + let highlighted_rows = editor.highlighted_rows(); + let theme = cx.global::().theme.as_ref(); + let highlighted_ranges = editor.background_highlights_in_range( + start_anchor..end_anchor, + &snapshot.display_snapshot, + theme, + ); - highlighted_rows = view.highlighted_rows(); - let theme = cx.global::().theme.as_ref(); - highlighted_ranges = - view.background_highlights_in_range(start_anchor..end_anchor, &display_map, theme); + 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), + ) + }), + ); - 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 remote_selections = HashMap::default(); + for (replica_id, line_mode, cursor_shape, selection) in snapshot + .buffer_snapshot + .remote_selections_in_range(&(start_anchor..end_anchor)) + { + // The local selections match the leader's selections. + if Some(replica_id) == editor.leader_replica_id { + continue; + } + remote_selections + .entry(replica_id) + .or_insert(Vec::new()) + .push(SelectionLayout::new( + selection, + line_mode, + cursor_shape, + &snapshot.display_snapshot, + )); + } + selections.extend(remote_selections); - let mut remote_selections = HashMap::default(); - for (replica_id, line_mode, cursor_shape, selection) in display_map - .buffer_snapshot - .remote_selections_in_range(&(start_anchor..end_anchor)) - { - // The local selections match the leader's selections. - if Some(replica_id) == view.leader_replica_id { - continue; + if editor.show_local_selections { + let mut local_selections = editor + .selections + .disjoint_in_range(start_anchor..end_anchor, cx); + local_selections.extend(editor.selections.pending(cx)); + for selection in &local_selections { + let is_empty = selection.start == selection.end; + let selection_start = snapshot.prev_line_boundary(selection.start).1; + let selection_end = snapshot.next_line_boundary(selection.end).1; + for row in cmp::max(selection_start.row(), start_row) + ..=cmp::min(selection_end.row(), end_row) + { + let contains_non_empty_selection = active_rows.entry(row).or_insert(!is_empty); + *contains_non_empty_selection |= !is_empty; } - remote_selections - .entry(replica_id) - .or_insert(Vec::new()) - .push(SelectionLayout::new( - selection, - line_mode, - cursor_shape, - &display_map, - )); } - selections.extend(remote_selections); - - if view.show_local_selections { - let mut local_selections = view - .selections - .disjoint_in_range(start_anchor..end_anchor, cx); - local_selections.extend(view.selections.pending(cx)); - for selection in &local_selections { - let is_empty = selection.start == selection.end; - let selection_start = snapshot.prev_line_boundary(selection.start).1; - let selection_end = snapshot.next_line_boundary(selection.end).1; - for row in cmp::max(selection_start.row(), start_row) - ..=cmp::min(selection_end.row(), end_row) - { - let contains_non_empty_selection = - active_rows.entry(row).or_insert(!is_empty); - *contains_non_empty_selection |= !is_empty; - } - } - // Render the local selections in the leader's color when following. - let local_replica_id = view - .leader_replica_id - .unwrap_or_else(|| view.replica_id(cx)); - - selections.push(( - local_replica_id, - local_selections - .into_iter() - .map(|selection| { - SelectionLayout::new( - selection, - view.selections.line_mode, - view.cursor_shape, - &display_map, - ) - }) - .collect(), - )); - } + // Render the local selections in the leader's color when following. + let local_replica_id = editor + .leader_replica_id + .unwrap_or_else(|| editor.replica_id(cx)); - show_scrollbars = view.scroll_manager.scrollbars_visible(); - include_root = view - .project - .as_ref() - .map(|project| project.read(cx).visible_worktrees(cx).count() > 1) - .unwrap_or_default() - }); + selections.push(( + local_replica_id, + local_selections + .into_iter() + .map(|selection| { + SelectionLayout::new( + selection, + editor.selections.line_mode, + editor.cursor_shape, + &snapshot.display_snapshot, + ) + }) + .collect(), + )); + } + + let show_scrollbars = editor.scroll_manager.scrollbars_visible(); + let include_root = editor + .project + .as_ref() + .map(|project| project.read(cx).visible_worktrees(cx).count() > 1) + .unwrap_or_default(); let fold_ranges: Vec<(BufferRow, Range, Color)> = fold_ranges .into_iter() @@ -1878,70 +1832,63 @@ impl Drawable for EditorElement { max_row as f32, ); - self.update_view(cx, |view, cx| { - let clamped = view.scroll_manager.clamp_scroll_left(scroll_max.x()); + let clamped = editor.scroll_manager.clamp_scroll_left(scroll_max.x()); - let autoscrolled = if autoscroll_horizontally { - view.autoscroll_horizontally( - start_row, - text_size.x(), - scroll_width, - em_width, - &line_layouts, - cx, - ) - } else { - false - }; + let autoscrolled = if autoscroll_horizontally { + editor.autoscroll_horizontally( + start_row, + text_size.x(), + scroll_width, + em_width, + &line_layouts, + cx, + ) + } else { + false + }; - if clamped || autoscrolled { - snapshot = view.snapshot(cx); - } - }); + if clamped || autoscrolled { + snapshot = editor.snapshot(cx); + } + + let newest_selection_head = editor + .selections + .newest::(cx) + .head() + .to_display_point(&snapshot); + let style = editor.style(cx); let mut context_menu = None; let mut code_actions_indicator = None; - let mut hover; - let mode; - let mut fold_indicators = { - let newest_selection_head = editor - .selections - .newest::(cx) - .head() - .to_display_point(&snapshot); - - let style = editor.style(cx); - if (start_row..end_row).contains(&newest_selection_head.row()) { - if editor.context_menu_visible() { - context_menu = - editor.render_context_menu(newest_selection_head, style.clone(), cx); - } + if (start_row..end_row).contains(&newest_selection_head.row()) { + if editor.context_menu_visible() { + context_menu = editor.render_context_menu(newest_selection_head, style.clone(), cx); + } - let active = matches!( - editor.context_menu, - Some(crate::ContextMenu::CodeActions(_)) - ); + let active = matches!( + editor.context_menu, + Some(crate::ContextMenu::CodeActions(_)) + ); - code_actions_indicator = editor - .render_code_actions_indicator(&style, active, cx) - .map(|indicator| (newest_selection_head.row(), indicator)); - } + code_actions_indicator = editor + .render_code_actions_indicator(&style, active, cx) + .map(|indicator| (newest_selection_head.row(), indicator)); + } - let visible_rows = start_row..start_row + line_layouts.len() as u32; - hover = editor - .hover_state - .render(&snapshot, &style, visible_rows, cx); - mode = editor.mode; - - editor.render_fold_indicators( - fold_statuses, - &style, - editor.gutter_hovered, - line_height, - gutter_margin, - cx, - ) - }; + let visible_rows = start_row..start_row + line_layouts.len() as u32; + let mut hover = editor + .hover_state + .render(&snapshot, &style, visible_rows, cx); + let mode = editor.mode; + + let mut fold_indicators = editor.render_fold_indicators( + fold_statuses, + &style, + editor.gutter_hovered, + line_height, + gutter_margin, + cx, + ); if let Some((_, context_menu)) = context_menu.as_mut() { context_menu.layout( @@ -2058,13 +2005,13 @@ impl Drawable for EditorElement { Self::attach_mouse_handlers( scene, - &self.view, &layout.position_map, layout.hover_popovers.is_some(), visible_bounds, text_bounds, gutter_bounds, bounds, + cx, ); self.paint_background(scene, gutter_bounds, text_bounds, layout); @@ -2563,7 +2510,7 @@ mod tests { let (_, editor) = cx.add_window(Default::default(), |cx| { Editor::new(EditorMode::Full, buffer, None, None, cx) }); - let element = EditorElement::new(editor.downgrade(), editor.read(cx).style(cx)); + let element = EditorElement::new(editor.read(cx).style(cx)); let layouts = editor.update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); @@ -2599,7 +2546,7 @@ mod tests { cx.blur(); }); - let mut element = EditorElement::new(editor.downgrade(), editor.read(cx).style(cx)); + let mut element = EditorElement::new(editor.read(cx).style(cx)); let (size, mut state) = editor.update(cx, |editor, cx| { element.layout( SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)),