diff --git a/Cargo.lock b/Cargo.lock index bdd7b7a1d9..c45b650d8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -841,17 +841,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "backtrace-on-stack-overflow" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd2d70527f3737a1ad17355e260706c1badebabd1fa06a7a053407380df841b" -dependencies = [ - "backtrace", - "libc", - "nix 0.23.2", -] - [[package]] name = "base64" version = "0.13.1" @@ -5570,19 +5559,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "nix" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" -dependencies = [ - "bitflags 1.3.2", - "cc", - "cfg-if 1.0.0", - "libc", - "memoffset 0.6.5", -] - [[package]] name = "nix" version = "0.24.3" @@ -8855,45 +8831,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "storybook2" -version = "0.1.0" -dependencies = [ - "anyhow", - "backtrace-on-stack-overflow", - "chrono", - "clap 4.4.4", - "editor2", - "fuzzy2", - "gpui2", - "itertools 0.11.0", - "language2", - "log", - "menu2", - "picker2", - "rust-embed", - "serde", - "settings2", - "simplelog", - "smallvec", - "strum", - "theme", - "theme2", - "ui2", - "util", -] - -[[package]] -name = "storybook3" -version = "0.1.0" -dependencies = [ - "anyhow", - "gpui2", - "settings2", - "theme2", - "ui2", -] - [[package]] name = "stringprep" version = "0.1.4" diff --git a/Cargo.toml b/Cargo.toml index 7c51d32d05..8bca4cd84e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,8 +96,8 @@ members = [ "crates/sqlez", "crates/sqlez_macros", "crates/rich_text", - "crates/storybook2", - "crates/storybook3", + # "crates/storybook2", + # "crates/storybook3", "crates/sum_tree", "crates/terminal", "crates/terminal2", diff --git a/crates/auto_update2/src/update_notification.rs b/crates/auto_update2/src/update_notification.rs index 03a71bcabb..e6a22b7324 100644 --- a/crates/auto_update2/src/update_notification.rs +++ b/crates/auto_update2/src/update_notification.rs @@ -8,8 +8,8 @@ pub struct UpdateNotification { impl EventEmitter for UpdateNotification {} -impl Render for UpdateNotification { - type Element = Div; +impl Render for UpdateNotification { + type Element = Div; fn render(&mut self, _cx: &mut gpui::ViewContext) -> Self::Element { div().child("Updated zed!") diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index 901348d2e2..6af188dfd2 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -3294,8 +3294,8 @@ impl CollabPanel { // .with_width(size.x()) // } -impl Render for CollabPanel { - type Element = Focusable>; +impl Render for CollabPanel { + type Element = Focusable
; fn render(&mut self, _cx: &mut ViewContext) -> Self::Element { div() diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index 42800269c7..2c08840691 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -81,8 +81,8 @@ pub struct CollabTitlebarItem { _subscriptions: Vec, } -impl Render for CollabTitlebarItem { - type Element = Stateful>; +impl Render for CollabTitlebarItem { + type Element = Stateful
; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { h_stack() @@ -100,7 +100,7 @@ impl Render for CollabTitlebarItem { |s| s.pl(px(68.)), ) .bg(cx.theme().colors().title_bar_background) - .on_click(|_, event, cx| { + .on_click(|event, cx| { if event.up.click_count == 2 { cx.zoom_window(); } @@ -117,14 +117,14 @@ impl Render for CollabTitlebarItem { .variant(ButtonVariant::Ghost) .color(Some(TextColor::Player(0))), ) - .tooltip(move |_, cx| Tooltip::text("Toggle following", cx)), + .tooltip(move |cx| Tooltip::text("Toggle following", cx)), ) // TODO - Add project menu .child( div() .id("titlebar_project_menu_button") .child(Button::new("project_name").variant(ButtonVariant::Ghost)) - .tooltip(move |_, cx| Tooltip::text("Recent Projects", cx)), + .tooltip(move |cx| Tooltip::text("Recent Projects", cx)), ) // TODO - Add git menu .child( @@ -135,7 +135,7 @@ impl Render for CollabTitlebarItem { .variant(ButtonVariant::Ghost) .color(Some(TextColor::Muted)), ) - .tooltip(move |_, cx| { + .tooltip(move |cx| { cx.build_view(|_| { Tooltip::new("Recent Branches") .key_binding(KeyBinding::new(gpui::KeyBinding::new( diff --git a/crates/command_palette2/src/command_palette.rs b/crates/command_palette2/src/command_palette.rs index 1296f35c55..3c6f2fff92 100644 --- a/crates/command_palette2/src/command_palette.rs +++ b/crates/command_palette2/src/command_palette.rs @@ -76,8 +76,8 @@ impl FocusableView for CommandPalette { } } -impl Render for CommandPalette { - type Element = Div; +impl Render for CommandPalette { + type Element = Div; fn render(&mut self, _cx: &mut ViewContext) -> Self::Element { v_stack().w_96().child(self.picker.clone()) @@ -140,7 +140,7 @@ impl CommandPaletteDelegate { } impl PickerDelegate for CommandPaletteDelegate { - type ListItem = Div>; + type ListItem = Div; fn placeholder_text(&self) -> Arc { "Execute a command...".into() diff --git a/crates/diagnostics2/src/diagnostics.rs b/crates/diagnostics2/src/diagnostics.rs index 7203748470..d19c8f7b12 100644 --- a/crates/diagnostics2/src/diagnostics.rs +++ b/crates/diagnostics2/src/diagnostics.rs @@ -16,7 +16,7 @@ use gpui::{ actions, div, AnyElement, AnyView, AppContext, Context, Div, EventEmitter, FocusEvent, FocusHandle, Focusable, FocusableElement, FocusableView, InteractiveElement, Model, ParentElement, Render, RenderOnce, SharedString, Styled, Subscription, Task, View, ViewContext, - VisualContext, WeakView, + VisualContext, WeakView, WindowContext, }; use language::{ Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, @@ -90,8 +90,8 @@ struct DiagnosticGroupState { impl EventEmitter for ProjectDiagnosticsEditor {} -impl Render for ProjectDiagnosticsEditor { - type Element = Focusable>; +impl Render for ProjectDiagnosticsEditor { + type Element = Focusable
; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let child = if self.path_states.is_empty() { @@ -109,8 +109,8 @@ impl Render for ProjectDiagnosticsEditor { div() .track_focus(&self.focus_handle) .size_full() - .on_focus_in(Self::focus_in) - .on_action(Self::toggle_warnings) + .on_focus_in(cx.listener(Self::focus_in)) + .on_action(cx.listener(Self::toggle_warnings)) .child(child) } } @@ -662,7 +662,7 @@ impl Item for ProjectDiagnosticsEditor { Some("Project Diagnostics".into()) } - fn tab_content(&self, _detail: Option, _: &AppContext) -> AnyElement { + fn tab_content(&self, _detail: Option, _: &WindowContext) -> AnyElement { render_summary(&self.summary) } @@ -796,11 +796,10 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock { }) } -pub(crate) fn render_summary(summary: &DiagnosticSummary) -> AnyElement { +pub(crate) fn render_summary(summary: &DiagnosticSummary) -> AnyElement { if summary.error_count == 0 && summary.warning_count == 0 { let label = Label::new("No problems"); label.render_into_any() - //.render() } else { h_stack() .bg(gpui::red()) diff --git a/crates/diagnostics2/src/items.rs b/crates/diagnostics2/src/items.rs index 1d5183634f..730927a79e 100644 --- a/crates/diagnostics2/src/items.rs +++ b/crates/diagnostics2/src/items.rs @@ -21,8 +21,8 @@ pub struct DiagnosticIndicator { _observe_active_editor: Option, } -impl Render for DiagnosticIndicator { - type Element = Stateful>; +impl Render for DiagnosticIndicator { + type Element = Stateful
; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let diagnostic_indicator = match (self.summary.error_count, self.summary.warning_count) { @@ -45,7 +45,7 @@ impl Render for DiagnosticIndicator { h_stack() .id(cx.entity_id()) - .on_action(Self::go_to_next_diagnostic) + .on_action(cx.listener(Self::go_to_next_diagnostic)) .rounded_md() .flex_none() .h(rems(1.375)) @@ -54,14 +54,14 @@ impl Render for DiagnosticIndicator { .bg(cx.theme().colors().ghost_element_background) .hover(|style| style.bg(cx.theme().colors().ghost_element_hover)) .active(|style| style.bg(cx.theme().colors().ghost_element_active)) - .tooltip(|_, cx| Tooltip::text("Project Diagnostics", cx)) - .on_click(|this, _, cx| { + .tooltip(|cx| Tooltip::text("Project Diagnostics", cx)) + .on_click(cx.listener(|this, _, cx| { if let Some(workspace) = this.workspace.upgrade() { workspace.update(cx, |workspace, cx| { ProjectDiagnosticsEditor::deploy(workspace, &Default::default(), cx) }) } - }) + })) .child(diagnostic_indicator) } } diff --git a/crates/diagnostics2/src/toolbar_controls.rs b/crates/diagnostics2/src/toolbar_controls.rs index a22217f0a1..f6c3ed996b 100644 --- a/crates/diagnostics2/src/toolbar_controls.rs +++ b/crates/diagnostics2/src/toolbar_controls.rs @@ -7,8 +7,8 @@ pub struct ToolbarControls { editor: Option>, } -impl Render for ToolbarControls { - type Element = Div; +impl Render for ToolbarControls { + type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let include_warnings = self @@ -26,14 +26,14 @@ impl Render for ToolbarControls { div().child( IconButton::new("toggle-warnings", Icon::ExclamationTriangle) - .tooltip(move |_, cx| Tooltip::text(tooltip, cx)) - .on_click(|this: &mut Self, cx| { + .tooltip(move |cx| Tooltip::text(tooltip, cx)) + .on_click(cx.listener(|this, _, cx| { if let Some(editor) = this.editor.as_ref().and_then(|editor| editor.upgrade()) { editor.update(cx, |editor, cx| { editor.toggle_warnings(&Default::default(), cx); }); } - }), + })), ) } } diff --git a/crates/editor2/src/display_map/block_map.rs b/crates/editor2/src/display_map/block_map.rs index 05106dd2a1..00778c2edd 100644 --- a/crates/editor2/src/display_map/block_map.rs +++ b/crates/editor2/src/display_map/block_map.rs @@ -50,7 +50,7 @@ struct BlockRow(u32); #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] struct WrapRow(u32); -pub type RenderBlock = Arc AnyElement>; +pub type RenderBlock = Arc AnyElement>; pub struct Block { id: BlockId, @@ -69,7 +69,7 @@ where pub position: P, pub height: u8, pub style: BlockStyle, - pub render: Arc AnyElement>, + pub render: Arc AnyElement>, pub disposition: BlockDisposition, } @@ -947,7 +947,7 @@ impl DerefMut for BlockContext<'_, '_> { } impl Block { - pub fn render(&self, cx: &mut BlockContext) -> AnyElement { + pub fn render(&self, cx: &mut BlockContext) -> AnyElement { self.render.lock()(cx) } diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 5e40f5368e..d3bbbff522 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -907,7 +907,7 @@ impl ContextMenu { style: &EditorStyle, workspace: Option>, cx: &mut ViewContext, - ) -> (DisplayPoint, AnyElement) { + ) -> (DisplayPoint, AnyElement) { match self { ContextMenu::Completions(menu) => (cursor_position, menu.render(style, workspace, cx)), ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx), @@ -1223,7 +1223,7 @@ impl CompletionsMenu { style: &EditorStyle, workspace: Option>, cx: &mut ViewContext, - ) -> AnyElement { + ) -> AnyElement { todo!("old implementation below") } @@ -1541,13 +1541,15 @@ impl CodeActionsMenu { mut cursor_position: DisplayPoint, style: &EditorStyle, cx: &mut ViewContext, - ) -> (DisplayPoint, AnyElement) { + ) -> (DisplayPoint, AnyElement) { let actions = self.actions.clone(); let selected_item = self.selected_item; + let element = uniform_list( + cx.view().clone(), "code_actions_menu", self.actions.len(), - move |editor, range, cx| { + move |this, range, cx| { actions[range.clone()] .iter() .enumerate() @@ -1569,17 +1571,20 @@ impl CodeActionsMenu { .bg(colors.element_hover) .text_color(colors.text_accent) }) - .on_mouse_down(MouseButton::Left, move |editor: &mut Editor, _, cx| { - cx.stop_propagation(); - editor - .confirm_code_action( - &ConfirmCodeAction { - item_ix: Some(item_ix), - }, - cx, - ) - .map(|task| task.detach_and_log_err(cx)); - }) + .on_mouse_down( + MouseButton::Left, + cx.listener(move |editor, _, cx| { + cx.stop_propagation(); + editor + .confirm_code_action( + &ConfirmCodeAction { + item_ix: Some(item_ix), + }, + cx, + ) + .map(|task| task.detach_and_log_err(cx)); + }), + ) // TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here. .child(SharedString::from(action.lsp_action.title.clone())) }) @@ -4354,11 +4359,11 @@ impl Editor { style: &EditorStyle, is_active: bool, cx: &mut ViewContext, - ) -> Option> { + ) -> Option { if self.available_code_actions.is_some() { Some( - IconButton::new("code_actions_indicator", ui::Icon::Bolt).on_click( - |editor: &mut Editor, cx| { + IconButton::new("code_actions_indicator", ui::Icon::Bolt).on_click(cx.listener( + |editor, e, cx| { editor.toggle_code_actions( &ToggleCodeActions { deployed_from_indicator: true, @@ -4366,7 +4371,7 @@ impl Editor { cx, ); }, - ), + )), ) } else { None @@ -4381,7 +4386,7 @@ impl Editor { line_height: Pixels, gutter_margin: Pixels, cx: &mut ViewContext, - ) -> Vec>> { + ) -> Vec> { fold_data .iter() .enumerate() @@ -4394,14 +4399,14 @@ impl Editor { FoldStatus::Foldable => ui::Icon::ChevronDown, }; IconButton::new(ix as usize, icon) - .on_click(move |editor: &mut Editor, cx| match fold_status { + .on_click(cx.listener(move |editor, e, cx| match fold_status { FoldStatus::Folded => { editor.unfold_at(&UnfoldAt { buffer_row }, cx); } FoldStatus::Foldable => { editor.fold_at(&FoldAt { buffer_row }, cx); } - }) + })) .color(ui::TextColor::Muted) }) }) @@ -4422,7 +4427,7 @@ impl Editor { cursor_position: DisplayPoint, style: &EditorStyle, cx: &mut ViewContext, - ) -> Option<(DisplayPoint, AnyElement)> { + ) -> Option<(DisplayPoint, AnyElement)> { self.context_menu.read().as_ref().map(|menu| { menu.render( cursor_position, @@ -7781,7 +7786,7 @@ impl Editor { } div() .pl(cx.anchor_x) - .child(rename_editor.render_with(EditorElement::new( + .child(EditorElement::new( &rename_editor, EditorStyle { background: cx.theme().system().transparent, @@ -7789,10 +7794,12 @@ impl Editor { text: text_style, scrollbar_width: cx.editor_style.scrollbar_width, syntax: cx.editor_style.syntax.clone(), - diagnostic_style: - cx.editor_style.diagnostic_style.clone(), + diagnostic_style: cx + .editor_style + .diagnostic_style + .clone(), }, - ))) + )) .render_into_any() } }), @@ -9382,7 +9389,7 @@ impl FocusableView for Editor { } } -impl Render for Editor { +impl Render for Editor { type Element = EditorElement; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { @@ -9996,10 +10003,10 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend .ml(cx.anchor_x) })) .cursor_pointer() - .on_click(move |_, _, cx| { + .on_click(cx.listener(move |_, _, cx| { cx.write_to_clipboard(ClipboardItem::new(message.clone())); - }) - .tooltip(|_, cx| Tooltip::text("Copy diagnostic message", cx)) + })) + .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)) .render_into_any() }) } diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index 42cb47da49..add9c9ad33 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -23,7 +23,7 @@ use gpui::{ ElementId, ElementInputHandler, Entity, EntityId, Hsla, InteractiveElement, LineLayout, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, RenderOnce, ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled, - TextRun, TextStyle, View, ViewContext, WindowContext, WrappedLine, + TextRun, TextStyle, View, ViewContext, WeakView, WindowContext, WrappedLine, }; use itertools::Itertools; use language::language_settings::ShowWhitespaceSetting; @@ -112,14 +112,14 @@ impl SelectionLayout { } pub struct EditorElement { - editor_id: EntityId, + editor: View, style: EditorStyle, } impl EditorElement { pub fn new(editor: &View, style: EditorStyle) -> Self { Self { - editor_id: editor.entity_id(), + editor: editor.clone(), style, } } @@ -349,7 +349,7 @@ impl EditorElement { gutter_bounds: Bounds, text_bounds: Bounds, layout: &LayoutState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let bounds = gutter_bounds.union(&text_bounds); let scroll_top = @@ -460,7 +460,7 @@ impl EditorElement { bounds: Bounds, layout: &mut LayoutState, editor: &mut Editor, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let line_height = layout.position_map.line_height; @@ -495,7 +495,7 @@ impl EditorElement { AvailableSpace::MinContent, AvailableSpace::Definite(line_height * 0.55), ); - let fold_indicator_size = fold_indicator.measure(available_space, editor, cx); + let fold_indicator_size = fold_indicator.measure(available_space, cx); let position = point( bounds.size.width - layout.gutter_padding, @@ -506,7 +506,7 @@ impl EditorElement { (line_height - fold_indicator_size.height) / 2., ); let origin = bounds.origin + position + centering_offset; - fold_indicator.draw(origin, available_space, editor, cx); + fold_indicator.draw(origin, available_space, cx); } } @@ -516,7 +516,7 @@ impl EditorElement { AvailableSpace::MinContent, AvailableSpace::Definite(line_height), ); - let indicator_size = button.measure(available_space, editor, cx); + let indicator_size = button.measure(available_space, cx); let mut x = Pixels::ZERO; let mut y = indicator.row as f32 * line_height - scroll_top; @@ -524,15 +524,11 @@ impl EditorElement { x += ((layout.gutter_padding + layout.gutter_margin) - indicator_size.width) / 2.; y += (line_height - indicator_size.height) / 2.; - button.draw(bounds.origin + point(x, y), available_space, editor, cx); + button.draw(bounds.origin + point(x, y), available_space, cx); } } - fn paint_diff_hunks( - bounds: Bounds, - layout: &LayoutState, - cx: &mut ViewContext, - ) { + fn paint_diff_hunks(bounds: Bounds, layout: &LayoutState, cx: &mut WindowContext) { // todo!() // let diff_style = &theme::current(cx).editor.diff.clone(); // let line_height = layout.position_map.line_height; @@ -621,7 +617,7 @@ impl EditorElement { text_bounds: Bounds, layout: &mut LayoutState, editor: &mut Editor, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let scroll_position = layout.position_map.snapshot.scroll_position(); let start_row = layout.visible_display_row_range.start; @@ -676,20 +672,22 @@ impl EditorElement { 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(); - }) + .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation()) + .on_click(cx.listener_for( + &self.editor, + 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() { @@ -852,7 +850,7 @@ impl EditorElement { .min((text_bounds.size.height - line_height) / 2.), ), ); - let context_menu_size = context_menu.measure(available_space, editor, cx); + let context_menu_size = context_menu.measure(available_space, cx); let cursor_row_layout = &layout.position_map.line_layouts [(position.row() - start_row) as usize] @@ -876,7 +874,7 @@ impl EditorElement { list_origin.y -= layout.position_map.line_height - list_height; } - context_menu.draw(list_origin, available_space, editor, cx); + context_menu.draw(list_origin, available_space, cx); }) } @@ -1167,7 +1165,7 @@ impl EditorElement { layout: &LayoutState, content_origin: gpui::Point, bounds: Bounds, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let start_row = layout.visible_display_row_range.start; let end_row = layout.visible_display_row_range.end; @@ -1220,7 +1218,7 @@ impl EditorElement { bounds: Bounds, layout: &mut LayoutState, editor: &mut Editor, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let scroll_position = layout.position_map.snapshot.scroll_position(); let scroll_left = scroll_position.x * layout.position_map.em_width; @@ -1235,9 +1233,7 @@ impl EditorElement { if !matches!(block.style, BlockStyle::Sticky) { origin += point(-scroll_left, Pixels::ZERO); } - block - .element - .draw(origin, block.available_space, editor, cx); + block.element.draw(origin, block.available_space, cx); } } @@ -2030,12 +2026,10 @@ impl EditorElement { let jump_position = language::ToPoint::to_point(&jump_anchor, buffer); IconButton::new(block_id, ui::Icon::ArrowUpRight) - .on_click(move |editor: &mut Editor, cx| { + .on_click(cx.listener_for(&self.editor, move |editor, e, cx| { editor.jump(jump_path.clone(), jump_position, jump_anchor, cx); - }) - .tooltip(move |_, cx| { - Tooltip::for_action("Jump to Buffer", &OpenExcerpts, cx) - }) + })) + .tooltip(|cx| Tooltip::for_action("Jump to Buffer", &OpenExcerpts, cx)) }); let element = if *starts_new_buffer { @@ -2074,7 +2068,7 @@ impl EditorElement { } }; - let size = element.measure(available_space, editor, cx); + let size = element.measure(available_space, cx); (element, size) }; @@ -2133,47 +2127,61 @@ impl EditorElement { gutter_bounds: Bounds, text_bounds: Bounds, layout: &LayoutState, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO); cx.on_mouse_event({ let position_map = layout.position_map.clone(); - move |editor, event: &ScrollWheelEvent, phase, cx| { + let editor = self.editor.clone(); + + move |event: &ScrollWheelEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } - if Self::scroll(editor, event, &position_map, bounds, cx) { + let should_cancel = editor.update(cx, |editor, cx| { + Self::scroll(editor, event, &position_map, bounds, cx) + }); + if should_cancel { cx.stop_propagation(); } } }); + cx.on_mouse_event({ let position_map = layout.position_map.clone(); - move |editor, event: &MouseDownEvent, phase, cx| { + let editor = self.editor.clone(); + + move |event: &MouseDownEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } - if Self::mouse_down(editor, event, &position_map, text_bounds, gutter_bounds, cx) { + let should_cancel = editor.update(cx, |editor, cx| { + Self::mouse_down(editor, event, &position_map, text_bounds, gutter_bounds, cx) + }); + + if should_cancel { cx.stop_propagation() } } }); + cx.on_mouse_event({ let position_map = layout.position_map.clone(); - move |editor, event: &MouseUpEvent, phase, cx| { - if phase != DispatchPhase::Bubble { - return; - } + let editor = self.editor.clone(); + move |event: &MouseUpEvent, phase, cx| { + let should_cancel = editor.update(cx, |editor, cx| { + Self::mouse_up(editor, event, &position_map, text_bounds, cx) + }); - if Self::mouse_up(editor, event, &position_map, text_bounds, cx) { + if should_cancel { cx.stop_propagation() } } }); - // todo!() + //todo!() // on_down(MouseButton::Right, { // let position_map = layout.position_map.clone(); // move |event, editor, cx| { @@ -2190,12 +2198,17 @@ impl EditorElement { // }); cx.on_mouse_event({ let position_map = layout.position_map.clone(); - move |editor, event: &MouseMoveEvent, phase, cx| { + let editor = self.editor.clone(); + move |event: &MouseMoveEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } - if Self::mouse_moved(editor, event, &position_map, text_bounds, gutter_bounds, cx) { + let stop_propogating = editor.update(cx, |editor, cx| { + Self::mouse_moved(editor, event, &position_map, text_bounds, gutter_bounds, cx) + }); + + if stop_propogating { cx.stop_propagation() } } @@ -2324,7 +2337,7 @@ impl LineWithInvisibles { content_origin: gpui::Point, whitespace_setting: ShowWhitespaceSetting, selection_ranges: &[Range], - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let line_height = layout.position_map.line_height; let line_y = line_height * row as f32 - layout.position_map.scroll_position.y; @@ -2356,7 +2369,7 @@ impl LineWithInvisibles { row: u32, line_height: Pixels, whitespace_setting: ShowWhitespaceSetting, - cx: &mut ViewContext, + cx: &mut WindowContext, ) { let allowed_invisibles_regions = match whitespace_setting { ShowWhitespaceSetting::None => return, @@ -2399,85 +2412,98 @@ enum Invisible { Whitespace { line_offset: usize }, } -impl Element for EditorElement { +impl Element for EditorElement { type State = (); fn layout( &mut self, - editor: &mut Editor, element_state: Option, - cx: &mut gpui::ViewContext, + cx: &mut gpui::WindowContext, ) -> (gpui::LayoutId, Self::State) { - editor.style = Some(self.style.clone()); // Long-term, we'd like to eliminate this. + self.editor.update(cx, |editor, cx| { + editor.style = Some(self.style.clone()); // Long-term, we'd like to eliminate this. - let rem_size = cx.rem_size(); - let mut style = Style::default(); - style.size.width = relative(1.).into(); - style.size.height = match editor.mode { - EditorMode::SingleLine => self.style.text.line_height_in_pixels(cx.rem_size()).into(), - EditorMode::AutoHeight { .. } => todo!(), - EditorMode::Full => relative(1.).into(), - }; - let layout_id = cx.request_layout(&style, None); - (layout_id, ()) + let rem_size = cx.rem_size(); + let mut style = Style::default(); + style.size.width = relative(1.).into(); + style.size.height = match editor.mode { + EditorMode::SingleLine => { + self.style.text.line_height_in_pixels(cx.rem_size()).into() + } + EditorMode::AutoHeight { .. } => todo!(), + EditorMode::Full => relative(1.).into(), + }; + let layout_id = cx.request_layout(&style, None); + + (layout_id, ()) + }) } fn paint( mut self, bounds: Bounds, - editor: &mut Editor, element_state: &mut Self::State, - cx: &mut gpui::ViewContext, + cx: &mut gpui::WindowContext, ) { - let mut layout = self.compute_layout(editor, cx, bounds); - let gutter_bounds = Bounds { - origin: bounds.origin, - size: layout.gutter_size, - }; - let text_bounds = Bounds { - origin: gutter_bounds.upper_right(), - size: layout.text_size, - }; + let editor = self.editor.clone(); + editor.update(cx, |editor, cx| { + let mut layout = self.compute_layout(editor, cx, bounds); + let gutter_bounds = Bounds { + origin: bounds.origin, + size: layout.gutter_size, + }; + let text_bounds = Bounds { + origin: gutter_bounds.upper_right(), + size: layout.text_size, + }; - let dispatch_context = editor.dispatch_context(cx); - cx.with_key_dispatch( - dispatch_context, - Some(editor.focus_handle.clone()), - |_, cx| { - register_actions(cx); + let dispatch_context = editor.dispatch_context(cx); + let editor_handle = cx.view().clone(); + cx.with_key_dispatch( + dispatch_context, + Some(editor.focus_handle.clone()), + |_, cx| { + register_actions(&editor_handle, cx); - // We call with_z_index to establish a new stacking context. - cx.with_z_index(0, |cx| { - cx.with_content_mask(Some(ContentMask { bounds }), |cx| { - // Paint mouse listeners first, so any elements we paint on top of the editor - // take precedence. - self.paint_mouse_listeners(bounds, gutter_bounds, text_bounds, &layout, cx); - let input_handler = ElementInputHandler::new(bounds, cx); - cx.handle_input(&editor.focus_handle, input_handler); + // We call with_z_index to establish a new stacking context. + cx.with_z_index(0, |cx| { + cx.with_content_mask(Some(ContentMask { bounds }), |cx| { + // Paint mouse listeners first, so any elements we paint on top of the editor + // take precedence. + self.paint_mouse_listeners( + bounds, + gutter_bounds, + text_bounds, + &layout, + cx, + ); + let input_handler = ElementInputHandler::new(bounds, editor_handle, cx); + cx.handle_input(&editor.focus_handle, input_handler); - self.paint_background(gutter_bounds, text_bounds, &layout, cx); - if layout.gutter_size.width > Pixels::ZERO { - self.paint_gutter(gutter_bounds, &mut layout, editor, cx); - } - self.paint_text(text_bounds, &mut layout, editor, cx); + self.paint_background(gutter_bounds, text_bounds, &layout, cx); + if layout.gutter_size.width > Pixels::ZERO { + self.paint_gutter(gutter_bounds, &mut layout, editor, cx); + } + self.paint_text(text_bounds, &mut layout, editor, cx); - if !layout.blocks.is_empty() { - cx.with_element_id(Some("editor_blocks"), |cx| { - self.paint_blocks(bounds, &mut layout, editor, cx); - }) - } + if !layout.blocks.is_empty() { + cx.with_element_id(Some("editor_blocks"), |cx| { + self.paint_blocks(bounds, &mut layout, editor, cx); + }) + } + }); }); - }); - }, - ) + }, + ) + }) } } -impl RenderOnce for EditorElement { +impl RenderOnce for EditorElement { type Element = Self; fn element_id(&self) -> Option { - Some(self.editor_id.into()) + self.editor.element_id() } fn render_once(self) -> Self::Element { @@ -3106,17 +3132,17 @@ pub struct LayoutState { show_scrollbars: bool, is_singleton: bool, max_row: u32, - context_menu: Option<(DisplayPoint, AnyElement)>, + context_menu: Option<(DisplayPoint, AnyElement)>, code_actions_indicator: Option, - // hover_popovers: Option<(DisplayPoint, Vec>)>, - fold_indicators: Vec>>, + // hover_popovers: Option<(DisplayPoint, Vec)>, + fold_indicators: Vec>, tab_invisible: ShapedLine, space_invisible: ShapedLine, } struct CodeActionsIndicator { row: u32, - button: IconButton, + button: IconButton, } struct PositionMap { @@ -3201,7 +3227,7 @@ impl PositionMap { struct BlockLayout { row: u32, - element: AnyElement, + element: AnyElement, available_space: Size, style: BlockStyle, } @@ -3906,187 +3932,191 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: Pixels) -> f32 { // } // } -fn register_actions(cx: &mut ViewContext) { - register_action(cx, Editor::move_left); - register_action(cx, Editor::move_right); - register_action(cx, Editor::move_down); - register_action(cx, Editor::move_up); +fn register_actions(view: &View, cx: &mut WindowContext) { + register_action(view, cx, Editor::move_left); + register_action(view, cx, Editor::move_right); + register_action(view, cx, Editor::move_down); + register_action(view, cx, Editor::move_up); // on_action(cx, Editor::new_file); todo!() // on_action(cx, Editor::new_file_in_direction); todo!() - register_action(cx, Editor::cancel); - register_action(cx, Editor::newline); - register_action(cx, Editor::newline_above); - register_action(cx, Editor::newline_below); - register_action(cx, Editor::backspace); - register_action(cx, Editor::delete); - register_action(cx, Editor::tab); - register_action(cx, Editor::tab_prev); - register_action(cx, Editor::indent); - register_action(cx, Editor::outdent); - register_action(cx, Editor::delete_line); - register_action(cx, Editor::join_lines); - register_action(cx, Editor::sort_lines_case_sensitive); - register_action(cx, Editor::sort_lines_case_insensitive); - register_action(cx, Editor::reverse_lines); - register_action(cx, Editor::shuffle_lines); - register_action(cx, Editor::convert_to_upper_case); - register_action(cx, Editor::convert_to_lower_case); - register_action(cx, Editor::convert_to_title_case); - register_action(cx, Editor::convert_to_snake_case); - register_action(cx, Editor::convert_to_kebab_case); - register_action(cx, Editor::convert_to_upper_camel_case); - register_action(cx, Editor::convert_to_lower_camel_case); - register_action(cx, Editor::delete_to_previous_word_start); - register_action(cx, Editor::delete_to_previous_subword_start); - register_action(cx, Editor::delete_to_next_word_end); - register_action(cx, Editor::delete_to_next_subword_end); - register_action(cx, Editor::delete_to_beginning_of_line); - register_action(cx, Editor::delete_to_end_of_line); - register_action(cx, Editor::cut_to_end_of_line); - register_action(cx, Editor::duplicate_line); - register_action(cx, Editor::move_line_up); - register_action(cx, Editor::move_line_down); - register_action(cx, Editor::transpose); - register_action(cx, Editor::cut); - register_action(cx, Editor::copy); - register_action(cx, Editor::paste); - register_action(cx, Editor::undo); - register_action(cx, Editor::redo); - register_action(cx, Editor::move_page_up); - register_action(cx, Editor::move_page_down); - register_action(cx, Editor::next_screen); - register_action(cx, Editor::scroll_cursor_top); - register_action(cx, Editor::scroll_cursor_center); - register_action(cx, Editor::scroll_cursor_bottom); - register_action(cx, |editor, _: &LineDown, cx| { + register_action(view, cx, Editor::cancel); + register_action(view, cx, Editor::newline); + register_action(view, cx, Editor::newline_above); + register_action(view, cx, Editor::newline_below); + register_action(view, cx, Editor::backspace); + register_action(view, cx, Editor::delete); + register_action(view, cx, Editor::tab); + register_action(view, cx, Editor::tab_prev); + register_action(view, cx, Editor::indent); + register_action(view, cx, Editor::outdent); + register_action(view, cx, Editor::delete_line); + register_action(view, cx, Editor::join_lines); + register_action(view, cx, Editor::sort_lines_case_sensitive); + register_action(view, cx, Editor::sort_lines_case_insensitive); + register_action(view, cx, Editor::reverse_lines); + register_action(view, cx, Editor::shuffle_lines); + register_action(view, cx, Editor::convert_to_upper_case); + register_action(view, cx, Editor::convert_to_lower_case); + register_action(view, cx, Editor::convert_to_title_case); + register_action(view, cx, Editor::convert_to_snake_case); + register_action(view, cx, Editor::convert_to_kebab_case); + register_action(view, cx, Editor::convert_to_upper_camel_case); + register_action(view, cx, Editor::convert_to_lower_camel_case); + register_action(view, cx, Editor::delete_to_previous_word_start); + register_action(view, cx, Editor::delete_to_previous_subword_start); + register_action(view, cx, Editor::delete_to_next_word_end); + register_action(view, cx, Editor::delete_to_next_subword_end); + register_action(view, cx, Editor::delete_to_beginning_of_line); + register_action(view, cx, Editor::delete_to_end_of_line); + register_action(view, cx, Editor::cut_to_end_of_line); + register_action(view, cx, Editor::duplicate_line); + register_action(view, cx, Editor::move_line_up); + register_action(view, cx, Editor::move_line_down); + register_action(view, cx, Editor::transpose); + register_action(view, cx, Editor::cut); + register_action(view, cx, Editor::copy); + register_action(view, cx, Editor::paste); + register_action(view, cx, Editor::undo); + register_action(view, cx, Editor::redo); + register_action(view, cx, Editor::move_page_up); + register_action(view, cx, Editor::move_page_down); + register_action(view, cx, Editor::next_screen); + register_action(view, cx, Editor::scroll_cursor_top); + register_action(view, cx, Editor::scroll_cursor_center); + register_action(view, cx, Editor::scroll_cursor_bottom); + register_action(view, cx, |editor, _: &LineDown, cx| { editor.scroll_screen(&ScrollAmount::Line(1.), cx) }); - register_action(cx, |editor, _: &LineUp, cx| { + register_action(view, cx, |editor, _: &LineUp, cx| { editor.scroll_screen(&ScrollAmount::Line(-1.), cx) }); - register_action(cx, |editor, _: &HalfPageDown, cx| { + register_action(view, cx, |editor, _: &HalfPageDown, cx| { editor.scroll_screen(&ScrollAmount::Page(0.5), cx) }); - register_action(cx, |editor, _: &HalfPageUp, cx| { + register_action(view, cx, |editor, _: &HalfPageUp, cx| { editor.scroll_screen(&ScrollAmount::Page(-0.5), cx) }); - register_action(cx, |editor, _: &PageDown, cx| { + register_action(view, cx, |editor, _: &PageDown, cx| { editor.scroll_screen(&ScrollAmount::Page(1.), cx) }); - register_action(cx, |editor, _: &PageUp, cx| { + register_action(view, cx, |editor, _: &PageUp, cx| { editor.scroll_screen(&ScrollAmount::Page(-1.), cx) }); - register_action(cx, Editor::move_to_previous_word_start); - register_action(cx, Editor::move_to_previous_subword_start); - register_action(cx, Editor::move_to_next_word_end); - register_action(cx, Editor::move_to_next_subword_end); - register_action(cx, Editor::move_to_beginning_of_line); - register_action(cx, Editor::move_to_end_of_line); - register_action(cx, Editor::move_to_start_of_paragraph); - register_action(cx, Editor::move_to_end_of_paragraph); - register_action(cx, Editor::move_to_beginning); - register_action(cx, Editor::move_to_end); - register_action(cx, Editor::select_up); - register_action(cx, Editor::select_down); - register_action(cx, Editor::select_left); - register_action(cx, Editor::select_right); - register_action(cx, Editor::select_to_previous_word_start); - register_action(cx, Editor::select_to_previous_subword_start); - register_action(cx, Editor::select_to_next_word_end); - register_action(cx, Editor::select_to_next_subword_end); - register_action(cx, Editor::select_to_beginning_of_line); - register_action(cx, Editor::select_to_end_of_line); - register_action(cx, Editor::select_to_start_of_paragraph); - register_action(cx, Editor::select_to_end_of_paragraph); - register_action(cx, Editor::select_to_beginning); - register_action(cx, Editor::select_to_end); - register_action(cx, Editor::select_all); - register_action(cx, |editor, action, cx| { + register_action(view, cx, Editor::move_to_previous_word_start); + register_action(view, cx, Editor::move_to_previous_subword_start); + register_action(view, cx, Editor::move_to_next_word_end); + register_action(view, cx, Editor::move_to_next_subword_end); + register_action(view, cx, Editor::move_to_beginning_of_line); + register_action(view, cx, Editor::move_to_end_of_line); + register_action(view, cx, Editor::move_to_start_of_paragraph); + register_action(view, cx, Editor::move_to_end_of_paragraph); + register_action(view, cx, Editor::move_to_beginning); + register_action(view, cx, Editor::move_to_end); + register_action(view, cx, Editor::select_up); + register_action(view, cx, Editor::select_down); + register_action(view, cx, Editor::select_left); + register_action(view, cx, Editor::select_right); + register_action(view, cx, Editor::select_to_previous_word_start); + register_action(view, cx, Editor::select_to_previous_subword_start); + register_action(view, cx, Editor::select_to_next_word_end); + register_action(view, cx, Editor::select_to_next_subword_end); + register_action(view, cx, Editor::select_to_beginning_of_line); + register_action(view, cx, Editor::select_to_end_of_line); + register_action(view, cx, Editor::select_to_start_of_paragraph); + register_action(view, cx, Editor::select_to_end_of_paragraph); + register_action(view, cx, Editor::select_to_beginning); + register_action(view, cx, Editor::select_to_end); + register_action(view, cx, Editor::select_all); + register_action(view, cx, |editor, action, cx| { editor.select_all_matches(action, cx).log_err(); }); - register_action(cx, Editor::select_line); - register_action(cx, Editor::split_selection_into_lines); - register_action(cx, Editor::add_selection_above); - register_action(cx, Editor::add_selection_below); - register_action(cx, |editor, action, cx| { + register_action(view, cx, Editor::select_line); + register_action(view, cx, Editor::split_selection_into_lines); + register_action(view, cx, Editor::add_selection_above); + register_action(view, cx, Editor::add_selection_below); + register_action(view, cx, |editor, action, cx| { editor.select_next(action, cx).log_err(); }); - register_action(cx, |editor, action, cx| { + register_action(view, cx, |editor, action, cx| { editor.select_previous(action, cx).log_err(); }); - register_action(cx, Editor::toggle_comments); - register_action(cx, Editor::select_larger_syntax_node); - register_action(cx, Editor::select_smaller_syntax_node); - register_action(cx, Editor::move_to_enclosing_bracket); - register_action(cx, Editor::undo_selection); - register_action(cx, Editor::redo_selection); - register_action(cx, Editor::go_to_diagnostic); - register_action(cx, Editor::go_to_prev_diagnostic); - register_action(cx, Editor::go_to_hunk); - register_action(cx, Editor::go_to_prev_hunk); - register_action(cx, Editor::go_to_definition); - register_action(cx, Editor::go_to_definition_split); - register_action(cx, Editor::go_to_type_definition); - register_action(cx, Editor::go_to_type_definition_split); - register_action(cx, Editor::fold); - register_action(cx, Editor::fold_at); - register_action(cx, Editor::unfold_lines); - register_action(cx, Editor::unfold_at); - register_action(cx, Editor::fold_selected_ranges); - register_action(cx, Editor::show_completions); - register_action(cx, Editor::toggle_code_actions); + register_action(view, cx, Editor::toggle_comments); + register_action(view, cx, Editor::select_larger_syntax_node); + register_action(view, cx, Editor::select_smaller_syntax_node); + register_action(view, cx, Editor::move_to_enclosing_bracket); + register_action(view, cx, Editor::undo_selection); + register_action(view, cx, Editor::redo_selection); + register_action(view, cx, Editor::go_to_diagnostic); + register_action(view, cx, Editor::go_to_prev_diagnostic); + register_action(view, cx, Editor::go_to_hunk); + register_action(view, cx, Editor::go_to_prev_hunk); + register_action(view, cx, Editor::go_to_definition); + register_action(view, cx, Editor::go_to_definition_split); + register_action(view, cx, Editor::go_to_type_definition); + register_action(view, cx, Editor::go_to_type_definition_split); + register_action(view, cx, Editor::fold); + register_action(view, cx, Editor::fold_at); + register_action(view, cx, Editor::unfold_lines); + register_action(view, cx, Editor::unfold_at); + register_action(view, cx, Editor::fold_selected_ranges); + register_action(view, cx, Editor::show_completions); + register_action(view, cx, Editor::toggle_code_actions); // on_action(cx, Editor::open_excerpts); todo!() - register_action(cx, Editor::toggle_soft_wrap); - register_action(cx, Editor::toggle_inlay_hints); - register_action(cx, Editor::reveal_in_finder); - register_action(cx, Editor::copy_path); - register_action(cx, Editor::copy_relative_path); - register_action(cx, Editor::copy_highlight_json); - register_action(cx, |editor, action, cx| { + register_action(view, cx, Editor::toggle_soft_wrap); + register_action(view, cx, Editor::toggle_inlay_hints); + register_action(view, cx, Editor::reveal_in_finder); + register_action(view, cx, Editor::copy_path); + register_action(view, cx, Editor::copy_relative_path); + register_action(view, cx, Editor::copy_highlight_json); + register_action(view, cx, |editor, action, cx| { editor .format(action, cx) .map(|task| task.detach_and_log_err(cx)); }); - register_action(cx, Editor::restart_language_server); - register_action(cx, Editor::show_character_palette); + register_action(view, cx, Editor::restart_language_server); + register_action(view, cx, Editor::show_character_palette); // on_action(cx, Editor::confirm_completion); todo!() - register_action(cx, |editor, action, cx| { + register_action(view, cx, |editor, action, cx| { editor .confirm_code_action(action, cx) .map(|task| task.detach_and_log_err(cx)); }); - register_action(cx, |editor, action, cx| { + register_action(view, cx, |editor, action, cx| { editor .rename(action, cx) .map(|task| task.detach_and_log_err(cx)); }); - register_action(cx, |editor, action, cx| { + register_action(view, cx, |editor, action, cx| { editor .confirm_rename(action, cx) .map(|task| task.detach_and_log_err(cx)); }); - register_action(cx, |editor, action, cx| { + register_action(view, cx, |editor, action, cx| { editor .find_all_references(action, cx) .map(|task| task.detach_and_log_err(cx)); }); - register_action(cx, Editor::next_copilot_suggestion); - register_action(cx, Editor::previous_copilot_suggestion); - register_action(cx, Editor::copilot_suggest); - register_action(cx, Editor::context_menu_first); - register_action(cx, Editor::context_menu_prev); - register_action(cx, Editor::context_menu_next); - register_action(cx, Editor::context_menu_last); + register_action(view, cx, Editor::next_copilot_suggestion); + register_action(view, cx, Editor::previous_copilot_suggestion); + register_action(view, cx, Editor::copilot_suggest); + register_action(view, cx, Editor::context_menu_first); + register_action(view, cx, Editor::context_menu_prev); + register_action(view, cx, Editor::context_menu_next); + register_action(view, cx, Editor::context_menu_last); } fn register_action( - cx: &mut ViewContext, + view: &View, + cx: &mut WindowContext, listener: impl Fn(&mut Editor, &T, &mut ViewContext) + 'static, ) { - cx.on_action(TypeId::of::(), move |editor, action, phase, cx| { + let view = view.clone(); + cx.on_action(TypeId::of::(), move |action, phase, cx| { let action = action.downcast_ref().unwrap(); if phase == DispatchPhase::Bubble { - listener(editor, action, cx); + view.update(cx, |editor, cx| { + listener(editor, action, cx); + }) } }) } diff --git a/crates/editor2/src/hover_popover.rs b/crates/editor2/src/hover_popover.rs index 5c8f403d4f..07d108cd65 100644 --- a/crates/editor2/src/hover_popover.rs +++ b/crates/editor2/src/hover_popover.rs @@ -422,7 +422,7 @@ impl HoverState { visible_rows: Range, workspace: Option>, cx: &mut ViewContext, - ) -> Option<(DisplayPoint, Vec>)> { + ) -> Option<(DisplayPoint, Vec)> { todo!("old version below") } // // If there is a diagnostic, position the popovers based on that. @@ -504,7 +504,7 @@ pub struct DiagnosticPopover { } impl DiagnosticPopover { - pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext) -> AnyElement { + pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext) -> AnyElement { todo!() // enum PrimaryDiagnostic {} diff --git a/crates/editor2/src/items.rs b/crates/editor2/src/items.rs index d503ac9f5c..01d8d437a3 100644 --- a/crates/editor2/src/items.rs +++ b/crates/editor2/src/items.rs @@ -10,7 +10,7 @@ use futures::future::try_join_all; use gpui::{ div, point, AnyElement, AppContext, AsyncAppContext, Entity, EntityId, EventEmitter, FocusHandle, Model, ParentElement, Pixels, SharedString, Styled, Subscription, Task, View, - ViewContext, VisualContext, WeakView, + ViewContext, VisualContext, WeakView, WindowContext, }; use language::{ proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt, @@ -584,7 +584,7 @@ impl Item for Editor { Some(path.to_string_lossy().to_string().into()) } - fn tab_content(&self, detail: Option, cx: &AppContext) -> AnyElement { + fn tab_content(&self, detail: Option, cx: &WindowContext) -> AnyElement { let theme = cx.theme(); AnyElement::new( diff --git a/crates/file_finder2/src/file_finder.rs b/crates/file_finder2/src/file_finder.rs index 2e7655298a..0b9157bb4f 100644 --- a/crates/file_finder2/src/file_finder.rs +++ b/crates/file_finder2/src/file_finder.rs @@ -117,8 +117,8 @@ impl FocusableView for FileFinder { self.picker.focus_handle(cx) } } -impl Render for FileFinder { - type Element = Div; +impl Render for FileFinder { + type Element = Div; fn render(&mut self, _cx: &mut ViewContext) -> Self::Element { v_stack().w_96().child(self.picker.clone()) @@ -530,7 +530,7 @@ impl FileFinderDelegate { } impl PickerDelegate for FileFinderDelegate { - type ListItem = Div>; + type ListItem = Div; fn placeholder_text(&self) -> Arc { "Search project files...".into() diff --git a/crates/go_to_line2/src/go_to_line.rs b/crates/go_to_line2/src/go_to_line.rs index 9b3666ea5c..4ba605c3c9 100644 --- a/crates/go_to_line2/src/go_to_line.rs +++ b/crates/go_to_line2/src/go_to_line.rs @@ -144,15 +144,15 @@ impl GoToLine { } } -impl Render for GoToLine { - type Element = Div; +impl Render for GoToLine { + type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { div() .elevation_2(cx) .key_context("GoToLine") - .on_action(Self::cancel) - .on_action(Self::confirm) + .on_action(cx.listener(Self::cancel)) + .on_action(cx.listener(Self::confirm)) .w_96() .child( v_stack() diff --git a/crates/gpui2/src/elements/uniform_list.rs b/crates/gpui2/src/elements/uniform_list.rs index 0c7e9eb3fd..b24b3935fa 100644 --- a/crates/gpui2/src/elements/uniform_list.rs +++ b/crates/gpui2/src/elements/uniform_list.rs @@ -1,7 +1,7 @@ use crate::{ point, px, size, AnyElement, AvailableSpace, Bounds, Element, ElementId, InteractiveElement, - InteractiveElementState, Interactivity, LayoutId, Pixels, Point, RenderOnce, Size, - StyleRefinement, Styled, WindowContext, + InteractiveElementState, Interactivity, LayoutId, Pixels, Point, Render, RenderOnce, Size, + StyleRefinement, Styled, View, ViewContext, WindowContext, }; use smallvec::SmallVec; use std::{cell::RefCell, cmp, ops::Range, rc::Rc}; @@ -10,30 +10,36 @@ use taffy::style::Overflow; /// uniform_list provides lazy rendering for a set of items that are of uniform height. /// When rendered into a container with overflow-y: hidden and a fixed (or max) height, /// uniform_list will only render the visibile subset of items. -pub fn uniform_list( +pub fn uniform_list( + view: View, id: I, item_count: usize, - f: impl 'static + Fn(Range, &mut WindowContext) -> Vec, + f: impl 'static + Fn(&mut V, Range, &mut ViewContext) -> Vec, ) -> UniformList where I: Into, R: RenderOnce, + V: Render, { let id = id.into(); let mut style = StyleRefinement::default(); style.overflow.y = Some(Overflow::Hidden); + let render_range = move |range, cx: &mut WindowContext| { + view.update(cx, |this, cx| { + f(this, range, cx) + .into_iter() + .map(|component| component.render_into_any()) + .collect() + }) + }; + UniformList { id: id.clone(), style, item_count, item_to_measure_index: 0, - render_items: Box::new(move |visible_range, cx| { - f(visible_range, cx) - .into_iter() - .map(|component| component.render_into_any()) - .collect() - }), + render_items: Box::new(render_range), interactivity: Interactivity { element_id: Some(id.into()), ..Default::default() diff --git a/crates/gpui2/src/input.rs b/crates/gpui2/src/input.rs index 140f724417..8592eeffeb 100644 --- a/crates/gpui2/src/input.rs +++ b/crates/gpui2/src/input.rs @@ -1,4 +1,6 @@ -use crate::{AsyncWindowContext, Bounds, Pixels, PlatformInputHandler, View, ViewContext}; +use crate::{ + AsyncWindowContext, Bounds, Pixels, PlatformInputHandler, View, ViewContext, WindowContext, +}; use std::ops::Range; /// Implement this trait to allow views to handle textual input when implementing an editor, field, etc. @@ -43,9 +45,9 @@ pub struct ElementInputHandler { impl ElementInputHandler { /// Used in [Element::paint] with the element's bounds and a view context for its /// containing view. - pub fn new(element_bounds: Bounds, cx: &mut ViewContext) -> Self { + pub fn new(element_bounds: Bounds, view: View, cx: &mut WindowContext) -> Self { ElementInputHandler { - view: cx.view().clone(), + view, element_bounds, cx: cx.to_async(), } diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index 734150ee58..9438a165d6 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -309,50 +309,6 @@ where } } -// pub struct RenderViewWith { -// view: View, -// element: Option, -// } - -// impl Element for RenderViewWith -// where -// E: 'static + Element, -// { -// type State = Option; - -// fn layout( -// &mut self, -// _: Option, -// cx: &mut WindowContext, -// ) -> (LayoutId, Self::State) { -// self.view.update(cx, |view, cx| { -// let mut element = self.element.take().unwrap().into_any(); -// let layout_id = element.layout(view, cx); -// (layout_id, Some(element)) -// }) -// } - -// fn paint(self, _: Bounds, element: &mut Self::ElementState, cx: &mut WindowContext) { -// element.paint(cx) -// } -// } - -// impl RenderOnce for RenderViewWith -// where -// E: 'static + Element, -// ParentV: 'static, -// { -// type Element = Self; - -// fn element_id(&self) -> Option { -// self.element.as_ref().unwrap().element_id() -// } - -// fn render_once(self) -> Self::Element { -// self -// } -// } - mod any_view { use crate::{AnyElement, AnyView, BorrowWindow, Element, LayoutId, Render, WindowContext}; diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 4e1eed464c..483a8fdbee 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1437,7 +1437,27 @@ impl<'a> WindowContext<'a> { .bindings_for_action(action) } - ///========== ELEMENT RELATED FUNCTIONS =========== + pub fn listener_for( + &self, + view: &View, + f: impl Fn(&mut V, &E, &mut ViewContext) + 'static, + ) -> impl Fn(&E, &mut WindowContext) + 'static { + let view = view.downgrade(); + move |e: &E, cx: &mut WindowContext| { + view.update(cx, |view, cx| f(view, e, cx)).ok(); + } + } + + pub fn constructor_for( + &self, + view: &View, + f: impl Fn(&mut V, &mut ViewContext) -> R + 'static, + ) -> impl Fn(&mut WindowContext) -> R + 'static { + let view = view.clone(); + move |cx: &mut WindowContext| view.update(cx, |view, cx| f(view, cx)) + } + + //========== ELEMENT RELATED FUNCTIONS =========== pub fn with_key_dispatch( &mut self, context: KeyContext, @@ -1477,6 +1497,21 @@ impl<'a> WindowContext<'a> { listener(event, cx); })); } + + /// Set an input handler, such as [ElementInputHandler], which interfaces with the + /// platform to receive textual input with proper integration with concerns such + /// as IME interactions. + pub fn handle_input( + &mut self, + focus_handle: &FocusHandle, + input_handler: impl PlatformInputHandler, + ) { + if focus_handle.is_focused(self) { + self.window + .platform_window + .set_input_handler(Box::new(input_handler)); + } + } } impl Context for WindowContext<'_> { @@ -1658,6 +1693,10 @@ pub trait BorrowWindow: BorrowMut + BorrowMut { self.borrow_mut() } + fn app(&self) -> &AppContext { + self.borrow() + } + fn window(&self) -> &Window { self.borrow() } @@ -2241,21 +2280,6 @@ impl<'a, V: 'static> ViewContext<'a, V> { }); } - /// Set an input handler, such as [ElementInputHandler], which interfaces with the - /// platform to receive textual input with proper integration with concerns such - /// as IME interactions. - pub fn handle_input( - &mut self, - focus_handle: &FocusHandle, - input_handler: impl PlatformInputHandler, - ) { - if focus_handle.is_focused(self) { - self.window - .platform_window - .set_input_handler(Box::new(input_handler)); - } - } - pub fn emit(&mut self, event: Evt) where Evt: 'static, @@ -2287,19 +2311,11 @@ impl<'a, V: 'static> ViewContext<'a, V> { &self, f: impl Fn(&mut V, &E, &mut ViewContext) + 'static, ) -> impl Fn(&E, &mut WindowContext) + 'static { - let view = self.view().clone(); + let view = self.view().downgrade(); move |e: &E, cx: &mut WindowContext| { - view.update(cx, |view, cx| f(view, e, cx)); + view.update(cx, |view, cx| f(view, e, cx)).ok(); } } - - pub fn constructor( - &self, - f: impl Fn(&mut V, &mut ViewContext) -> R + 'static, - ) -> impl Fn(&mut WindowContext) -> R { - let view = self.view().clone(); - move |cx: &mut WindowContext| view.update(cx, |view, cx| f(view, cx)) - } } impl Context for ViewContext<'_, V> { diff --git a/crates/picker2/src/picker2.rs b/crates/picker2/src/picker2.rs index f29312234c..786e641ee8 100644 --- a/crates/picker2/src/picker2.rs +++ b/crates/picker2/src/picker2.rs @@ -1,7 +1,7 @@ use editor::Editor; use gpui::{ div, prelude::*, uniform_list, AppContext, Div, FocusHandle, FocusableView, MouseButton, - Render, Task, UniformListScrollHandle, View, ViewContext, WindowContext, + MouseDownEvent, Render, Task, UniformListScrollHandle, View, ViewContext, WindowContext, }; use std::{cmp, sync::Arc}; use ui::{prelude::*, v_stack, Divider, Label, TextColor}; @@ -15,7 +15,7 @@ pub struct Picker { } pub trait PickerDelegate: Sized + 'static { - type ListItem: RenderOnce>; + type ListItem: RenderOnce; fn match_count(&self) -> usize; fn selected_index(&self) -> usize; @@ -180,21 +180,21 @@ impl Picker { } } -impl Render for Picker { - type Element = Div; +impl Render for Picker { + type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { div() .key_context("picker") .size_full() .elevation_2(cx) - .on_action(Self::select_next) - .on_action(Self::select_prev) - .on_action(Self::select_first) - .on_action(Self::select_last) - .on_action(Self::cancel) - .on_action(Self::confirm) - .on_action(Self::secondary_confirm) + .on_action(cx.listener(Self::select_next)) + .on_action(cx.listener(Self::select_prev)) + .on_action(cx.listener(Self::select_first)) + .on_action(cx.listener(Self::select_last)) + .on_action(cx.listener(Self::cancel)) + .on_action(cx.listener(Self::confirm)) + .on_action(cx.listener(Self::secondary_confirm)) .child( v_stack() .py_0p5() @@ -208,31 +208,37 @@ impl Render for Picker { .p_1() .grow() .child( - uniform_list("candidates", self.delegate.match_count(), { - move |this: &mut Self, visible_range, cx| { - let selected_ix = this.delegate.selected_index(); - visible_range - .map(|ix| { - div() - .on_mouse_down( - MouseButton::Left, - move |this: &mut Self, event, cx| { - this.handle_click( - ix, - event.modifiers.command, - cx, - ) - }, - ) - .child(this.delegate.render_match( - ix, - ix == selected_ix, - cx, - )) - }) - .collect() - } - }) + uniform_list( + cx.view().clone(), + "candidates", + self.delegate.match_count(), + { + let selected_index = self.delegate.selected_index(); + + move |picker, visible_range, cx| { + visible_range + .map(|ix| { + div() + .on_mouse_down( + MouseButton::Left, + cx.listener(move |this, event: &MouseDownEvent, cx| { + this.handle_click( + ix, + event.modifiers.command, + cx, + ) + }), + ) + .child(picker.delegate.render_match( + ix, + ix == selected_index, + cx, + )) + }) + .collect() + } + }, + ) .track_scroll(self.scroll_handle.clone()), ) .max_h_72() diff --git a/crates/project_panel2/src/project_panel.rs b/crates/project_panel2/src/project_panel.rs index da3ada4c10..4d1a6ee8f7 100644 --- a/crates/project_panel2/src/project_panel.rs +++ b/crates/project_panel2/src/project_panel.rs @@ -10,9 +10,9 @@ use anyhow::{anyhow, Result}; use gpui::{ actions, div, px, uniform_list, Action, AppContext, AssetSource, AsyncWindowContext, ClipboardItem, Div, EventEmitter, FocusHandle, Focusable, FocusableView, InteractiveElement, - Model, MouseButton, ParentElement, Pixels, Point, PromptLevel, Render, RenderOnce, Stateful, - StatefulInteractiveElement, Styled, Task, UniformListScrollHandle, View, ViewContext, - VisualContext as _, WeakView, WindowContext, + Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, + RenderOnce, Stateful, StatefulInteractiveElement, Styled, Task, UniformListScrollHandle, View, + ViewContext, VisualContext as _, WeakView, WindowContext, }; use menu::{Confirm, SelectNext, SelectPrev}; use project::{ @@ -1339,7 +1339,7 @@ impl ProjectPanel { editor: Option<&View>, padding: Pixels, cx: &mut ViewContext, - ) -> Div { + ) -> Div { let show_editor = details.is_editing && !details.is_processing; let theme = cx.theme(); @@ -1378,7 +1378,7 @@ impl ProjectPanel { details: EntryDetails, // dragged_entry_destination: &mut Option>, cx: &mut ViewContext, - ) -> Stateful> { + ) -> Stateful
{ let kind = details.kind; let settings = ProjectPanelSettings::get_global(cx); const INDENT_SIZE: Pixels = px(16.0); @@ -1396,7 +1396,7 @@ impl ProjectPanel { this.bg(cx.theme().colors().element_selected) }) .hover(|style| style.bg(cx.theme().colors().element_hover)) - .on_click(move |this, event, cx| { + .on_click(cx.listener(move |this, event: &gpui::ClickEvent, cx| { if !show_editor { if kind.is_dir() { this.toggle_expanded(entry_id, cx); @@ -1408,10 +1408,13 @@ impl ProjectPanel { } } } - }) - .on_mouse_down(MouseButton::Right, move |this, event, cx| { - this.deploy_context_menu(event.position, entry_id, cx); - }) + })) + .on_mouse_down( + MouseButton::Right, + cx.listener(move |this, event: &MouseDownEvent, cx| { + this.deploy_context_menu(event.position, entry_id, cx); + }), + ) // .on_drop::(|this, event, cx| { // this.move_entry( // *dragged_entry, @@ -1423,10 +1426,10 @@ impl ProjectPanel { } } -impl Render for ProjectPanel { - type Element = Focusable>>; +impl Render for ProjectPanel { + type Element = Focusable>; - fn render(&mut self, _cx: &mut gpui::ViewContext) -> Self::Element { + fn render(&mut self, cx: &mut gpui::ViewContext) -> Self::Element { let has_worktree = self.visible_entries.len() != 0; if has_worktree { @@ -1434,40 +1437,43 @@ impl Render for ProjectPanel { .id("project-panel") .size_full() .key_context("ProjectPanel") - .on_action(Self::select_next) - .on_action(Self::select_prev) - .on_action(Self::expand_selected_entry) - .on_action(Self::collapse_selected_entry) - .on_action(Self::collapse_all_entries) - .on_action(Self::new_file) - .on_action(Self::new_directory) - .on_action(Self::rename) - .on_action(Self::delete) - .on_action(Self::confirm) - .on_action(Self::open_file) - .on_action(Self::cancel) - .on_action(Self::cut) - .on_action(Self::copy) - .on_action(Self::copy_path) - .on_action(Self::copy_relative_path) - .on_action(Self::paste) - .on_action(Self::reveal_in_finder) - .on_action(Self::open_in_terminal) - .on_action(Self::new_search_in_directory) + .on_action(cx.listener(Self::select_next)) + .on_action(cx.listener(Self::select_prev)) + .on_action(cx.listener(Self::expand_selected_entry)) + .on_action(cx.listener(Self::collapse_selected_entry)) + .on_action(cx.listener(Self::collapse_all_entries)) + .on_action(cx.listener(Self::new_file)) + .on_action(cx.listener(Self::new_directory)) + .on_action(cx.listener(Self::rename)) + .on_action(cx.listener(Self::delete)) + .on_action(cx.listener(Self::confirm)) + .on_action(cx.listener(Self::open_file)) + .on_action(cx.listener(Self::cancel)) + .on_action(cx.listener(Self::cut)) + .on_action(cx.listener(Self::copy)) + .on_action(cx.listener(Self::copy_path)) + .on_action(cx.listener(Self::copy_relative_path)) + .on_action(cx.listener(Self::paste)) + .on_action(cx.listener(Self::reveal_in_finder)) + .on_action(cx.listener(Self::open_in_terminal)) + .on_action(cx.listener(Self::new_search_in_directory)) .track_focus(&self.focus_handle) .child( uniform_list( + cx.view().clone(), "entries", self.visible_entries .iter() .map(|(_, worktree_entries)| worktree_entries.len()) .sum(), - |this: &mut Self, range, cx| { - let mut items = Vec::new(); - this.for_each_visible_entry(range, cx, |id, details, cx| { - items.push(this.render_entry(id, details, cx)); - }); - items + { + |this, range, cx| { + let mut items = Vec::new(); + this.for_each_visible_entry(range, cx, |id, details, cx| { + items.push(this.render_entry(id, details, cx)); + }); + items + } }, ) .size_full() diff --git a/crates/rich_text2/src/rich_text.rs b/crates/rich_text2/src/rich_text.rs index 48b530b7c5..4f64654bd3 100644 --- a/crates/rich_text2/src/rich_text.rs +++ b/crates/rich_text2/src/rich_text.rs @@ -56,12 +56,12 @@ pub struct Mention { } impl RichText { - pub fn element( + pub fn element( &self, // syntax: Arc, // style: RichTextStyle, // cx: &mut ViewContext, - ) -> AnyElement { + ) -> AnyElement { todo!(); // let mut region_id = 0; diff --git a/crates/storybook2/src/stories/colors.rs b/crates/storybook2/src/stories/colors.rs index b690435e01..8a628a01da 100644 --- a/crates/storybook2/src/stories/colors.rs +++ b/crates/storybook2/src/stories/colors.rs @@ -5,8 +5,8 @@ use ui::prelude::*; pub struct ColorsStory; -impl Render for ColorsStory { - type Element = Div; +impl Render for ColorsStory { + type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let color_scales = default_color_scales(); diff --git a/crates/storybook2/src/stories/focus.rs b/crates/storybook2/src/stories/focus.rs index 12c7ea81a0..7ddeec08bf 100644 --- a/crates/storybook2/src/stories/focus.rs +++ b/crates/storybook2/src/stories/focus.rs @@ -27,7 +27,7 @@ impl FocusStory { } impl Render for FocusStory { - type Element = Focusable>>; + type Element = Focusable>; fn render(&mut self, cx: &mut gpui::ViewContext) -> Self::Element { let theme = cx.theme(); @@ -42,18 +42,20 @@ impl Render for FocusStory { .id("parent") .focusable() .key_context("parent") - .on_action(|_, action: &ActionA, cx| { + .on_action(cx.listener(|_, action: &ActionA, cx| { println!("Action A dispatched on parent"); - }) - .on_action(|_, action: &ActionB, cx| { + })) + .on_action(cx.listener(|_, action: &ActionB, cx| { println!("Action B dispatched on parent"); - }) - .on_focus(|_, _, _| println!("Parent focused")) - .on_blur(|_, _, _| println!("Parent blurred")) - .on_focus_in(|_, _, _| println!("Parent focus_in")) - .on_focus_out(|_, _, _| println!("Parent focus_out")) - .on_key_down(|_, event, phase, _| println!("Key down on parent {:?}", event)) - .on_key_up(|_, event, phase, _| println!("Key up on parent {:?}", event)) + })) + .on_focus(cx.listener(|_, _, _| println!("Parent focused"))) + .on_blur(cx.listener(|_, _, _| println!("Parent blurred"))) + .on_focus_in(cx.listener(|_, _, _| println!("Parent focus_in"))) + .on_focus_out(cx.listener(|_, _, _| println!("Parent focus_out"))) + .on_key_down( + cx.listener(|_, event, phase, _| println!("Key down on parent {:?}", event)), + ) + .on_key_up(cx.listener(|_, event, phase, _| println!("Key up on parent {:?}", event))) .size_full() .bg(color_1) .focus(|style| style.bg(color_2)) @@ -61,38 +63,42 @@ impl Render for FocusStory { div() .track_focus(&self.child_1_focus) .key_context("child-1") - .on_action(|_, action: &ActionB, cx| { + .on_action(cx.listener(|_, action: &ActionB, cx| { println!("Action B dispatched on child 1 during"); - }) + })) .w_full() .h_6() .bg(color_4) .focus(|style| style.bg(color_5)) .in_focus(|style| style.bg(color_6)) - .on_focus(|_, _, _| println!("Child 1 focused")) - .on_blur(|_, _, _| println!("Child 1 blurred")) - .on_focus_in(|_, _, _| println!("Child 1 focus_in")) - .on_focus_out(|_, _, _| println!("Child 1 focus_out")) - .on_key_down(|_, event, phase, _| println!("Key down on child 1 {:?}", event)) - .on_key_up(|_, event, phase, _| println!("Key up on child 1 {:?}", event)) + .on_focus(cx.listener(|_, _, _| println!("Child 1 focused"))) + .on_blur(cx.listener(|_, _, _| println!("Child 1 blurred"))) + .on_focus_in(cx.listener(|_, _, _| println!("Child 1 focus_in"))) + .on_focus_out(cx.listener(|_, _, _| println!("Child 1 focus_out"))) + .on_key_down( + cx.listener(|_, event, _| println!("Key down on child 1 {:?}", event)), + ) + .on_key_up(cx.listener(|_, event, _| println!("Key up on child 1 {:?}", event))) .child("Child 1"), ) .child( div() .track_focus(&self.child_2_focus) .key_context("child-2") - .on_action(|_, action: &ActionC, cx| { + .on_action(cx.listener(|_, action: &ActionC, cx| { println!("Action C dispatched on child 2"); - }) + })) .w_full() .h_6() .bg(color_4) - .on_focus(|_, _, _| println!("Child 2 focused")) - .on_blur(|_, _, _| println!("Child 2 blurred")) - .on_focus_in(|_, _, _| println!("Child 2 focus_in")) - .on_focus_out(|_, _, _| println!("Child 2 focus_out")) - .on_key_down(|_, event, phase, _| println!("Key down on child 2 {:?}", event)) - .on_key_up(|_, event, phase, _| println!("Key up on child 2 {:?}", event)) + .on_focus(cx.listener(|_, _, _| println!("Child 2 focused"))) + .on_blur(cx.listener(|_, _, _| println!("Child 2 blurred"))) + .on_focus_in(cx.listener(|_, _, _| println!("Child 2 focus_in"))) + .on_focus_out(cx.listener(|_, _, _| println!("Child 2 focus_out"))) + .on_key_down( + cx.listener(|_, event, _| println!("Key down on child 2 {:?}", event)), + ) + .on_key_up(cx.listener(|_, event, _| println!("Key up on child 2 {:?}", event))) .child("Child 2"), ) } diff --git a/crates/storybook2/src/stories/kitchen_sink.rs b/crates/storybook2/src/stories/kitchen_sink.rs index 2d31cefed6..b59e00bf25 100644 --- a/crates/storybook2/src/stories/kitchen_sink.rs +++ b/crates/storybook2/src/stories/kitchen_sink.rs @@ -11,8 +11,8 @@ impl KitchenSinkStory { } } -impl Render for KitchenSinkStory { - type Element = Stateful>; +impl Render for KitchenSinkStory { + type Element = Stateful
; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let component_stories = ComponentStory::iter() diff --git a/crates/storybook2/src/stories/text.rs b/crates/storybook2/src/stories/text.rs index 716004dea7..c26e5fd3f1 100644 --- a/crates/storybook2/src/stories/text.rs +++ b/crates/storybook2/src/stories/text.rs @@ -11,8 +11,8 @@ impl TextStory { } } -impl Render for TextStory { - type Element = Div; +impl Render for TextStory { + type Element = Div; fn render(&mut self, cx: &mut gpui::ViewContext) -> Self::Element { v_stack() diff --git a/crates/terminal_view2/src/terminal_panel.rs b/crates/terminal_view2/src/terminal_panel.rs index 46885913ed..b6582b07b1 100644 --- a/crates/terminal_view2/src/terminal_panel.rs +++ b/crates/terminal_view2/src/terminal_panel.rs @@ -335,8 +335,8 @@ impl TerminalPanel { impl EventEmitter for TerminalPanel {} -impl Render for TerminalPanel { - type Element = Div; +impl Render for TerminalPanel { + type Element = Div; fn render(&mut self, _cx: &mut ViewContext) -> Self::Element { div().child(self.pane.clone()) diff --git a/crates/terminal_view2/src/terminal_view.rs b/crates/terminal_view2/src/terminal_view.rs index 3cbea11072..940be69da0 100644 --- a/crates/terminal_view2/src/terminal_view.rs +++ b/crates/terminal_view2/src/terminal_view.rs @@ -9,10 +9,10 @@ pub mod terminal_panel; // use crate::terminal_element::TerminalElement; use editor::{scroll::autoscroll::Autoscroll, Editor}; use gpui::{ - actions, div, Action, AnyElement, AppContext, DispatchPhase, Div, Element, EventEmitter, - FocusEvent, FocusHandle, Focusable, FocusableElement, FocusableView, InputHandler, - InteractiveElement, KeyDownEvent, Keystroke, Model, MouseButton, ParentElement, Pixels, Render, - SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView, + actions, div, Action, AnyElement, AppContext, Div, Element, EventEmitter, FocusEvent, + FocusHandle, Focusable, FocusableElement, FocusableView, InputHandler, InteractiveElement, + KeyDownEvent, Keystroke, Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Render, + SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView, WindowContext, }; use language::Bias; use persistence::TERMINAL_DB; @@ -84,7 +84,7 @@ pub struct TerminalView { has_new_content: bool, //Currently using iTerm bell, show bell emoji in tab until input is received has_bell: bool, - context_menu: Option>>, + context_menu: Option>, blink_state: bool, blinking_on: bool, blinking_paused: bool, @@ -505,12 +505,7 @@ pub fn regex_search_for_query(query: &project::search::SearchQuery) -> Option, - ) { + fn key_down(&mut self, event: &KeyDownEvent, cx: &mut ViewContext) { self.clear_bel(cx); self.pause_cursor_blinking(cx); @@ -537,8 +532,8 @@ impl TerminalView { } } -impl Render for TerminalView { - type Element = Focusable>; +impl Render for TerminalView { + type Element = Focusable
; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let terminal_handle = self.terminal.clone().downgrade(); @@ -552,14 +547,14 @@ impl Render for TerminalView { div() .z_index(0) .absolute() - .on_key_down(Self::key_down) - .on_action(TerminalView::send_text) - .on_action(TerminalView::send_keystroke) - .on_action(TerminalView::copy) - .on_action(TerminalView::paste) - .on_action(TerminalView::clear) - .on_action(TerminalView::show_character_palette) - .on_action(TerminalView::select_all) + .on_key_down(cx.listener(Self::key_down)) + .on_action(cx.listener(TerminalView::send_text)) + .on_action(cx.listener(TerminalView::send_keystroke)) + .on_action(cx.listener(TerminalView::copy)) + .on_action(cx.listener(TerminalView::paste)) + .on_action(cx.listener(TerminalView::clear)) + .on_action(cx.listener(TerminalView::show_character_palette)) + .on_action(cx.listener(TerminalView::select_all)) // todo!() .child( "TERMINAL HERE", // TerminalElement::new( @@ -569,10 +564,13 @@ impl Render for TerminalView { // self.can_navigate_to_selected_word, // ) ) - .on_mouse_down(MouseButton::Right, |this, event, cx| { - this.deploy_context_menu(event.position, cx); - cx.notify(); - }), + .on_mouse_down( + MouseButton::Right, + cx.listener(|this, event: &MouseDownEvent, cx| { + this.deploy_context_menu(event.position, cx); + cx.notify(); + }), + ), ) .children( self.context_menu @@ -580,8 +578,8 @@ impl Render for TerminalView { .map(|context_menu| div().z_index(1).absolute().child(context_menu)), ) .track_focus(&self.focus_handle) - .on_focus_in(Self::focus_in) - .on_focus_out(Self::focus_out) + .on_focus_in(cx.listener(Self::focus_in)) + .on_focus_out(cx.listener(Self::focus_out)) } } @@ -746,11 +744,7 @@ impl Item for TerminalView { Some(self.terminal().read(cx).title().into()) } - fn tab_content( - &self, - _detail: Option, - cx: &gpui::AppContext, - ) -> AnyElement { + fn tab_content(&self, _detail: Option, cx: &WindowContext) -> AnyElement { let title = self.terminal().read(cx).title(); div() diff --git a/crates/theme2/src/story.rs b/crates/theme2/src/story.rs index e0c802fcc7..5e484e12cd 100644 --- a/crates/theme2/src/story.rs +++ b/crates/theme2/src/story.rs @@ -1,11 +1,11 @@ -use gpui::{div, Div, Element, ParentElement, SharedString, Styled, ViewContext}; +use gpui::{div, Div, Element, ParentElement, SharedString, Styled, WindowContext}; use crate::ActiveTheme; pub struct Story {} impl Story { - pub fn container(cx: &mut ViewContext) -> Div { + pub fn container(cx: &mut WindowContext) -> Div { div() .size_full() .flex() @@ -16,21 +16,18 @@ impl Story { .bg(cx.theme().colors().background) } - pub fn title(cx: &mut ViewContext, title: SharedString) -> impl Element { + pub fn title(cx: &mut WindowContext, title: SharedString) -> impl Element { div() .text_xl() .text_color(cx.theme().colors().text) .child(title) } - pub fn title_for(cx: &mut ViewContext) -> impl Element { + pub fn title_for(cx: &mut WindowContext) -> impl Element { Self::title(cx, std::any::type_name::().into()) } - pub fn label( - cx: &mut ViewContext, - label: impl Into, - ) -> impl Element { + pub fn label(cx: &mut WindowContext, label: impl Into) -> impl Element { div() .mt_4() .mb_2() diff --git a/crates/theme2/src/styles/players.rs b/crates/theme2/src/styles/players.rs index 726e4bac56..a4734d1c00 100644 --- a/crates/theme2/src/styles/players.rs +++ b/crates/theme2/src/styles/players.rs @@ -147,8 +147,8 @@ mod stories { pub struct PlayerStory; - impl Render for PlayerStory { - type Element = Div; + impl Render for PlayerStory { + type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx).child( @@ -156,7 +156,7 @@ mod stories { .flex() .flex_col() .gap_4() - .child(Story::title_for::<_, PlayerColors>(cx)) + .child(Story::title_for::(cx)) .child(Story::label(cx, "Player Colors")) .child( div() diff --git a/crates/theme2/src/theme2.rs b/crates/theme2/src/theme2.rs index fb89604865..39c5924fb9 100644 --- a/crates/theme2/src/theme2.rs +++ b/crates/theme2/src/theme2.rs @@ -63,6 +63,12 @@ impl ActiveTheme for AppContext { } } +// impl<'a> ActiveTheme for WindowContext<'a> { +// fn theme(&self) -> &Arc { +// &ThemeSettings::get_global(self.app()).active_theme +// } +// } + pub struct ThemeFamily { pub id: String, pub name: SharedString, diff --git a/crates/ui2/src/components/avatar.rs b/crates/ui2/src/components/avatar.rs index da76a95cfa..2c2679c39a 100644 --- a/crates/ui2/src/components/avatar.rs +++ b/crates/ui2/src/components/avatar.rs @@ -7,10 +7,10 @@ pub struct Avatar { shape: Shape, } -impl Component for Avatar { - type Rendered = Img; +impl Component for Avatar { + type Rendered = Img; - fn render(self, _view: &mut V, cx: &mut ViewContext) -> Self::Rendered { + fn render(self, _: &mut WindowContext) -> Self::Rendered { let mut img = img(); if self.shape == Shape::Circle { @@ -51,12 +51,12 @@ mod stories { pub struct AvatarStory; - impl Render for AvatarStory { - type Element = Div; + impl Render for AvatarStory { + type Element = Div; - fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + fn render(&mut self, cx: &mut WindowContext) -> Self::Element { Story::container(cx) - .child(Story::title_for::<_, Avatar>(cx)) + .child(Story::title_for::(cx)) .child(Story::label(cx, "Default")) .child(Avatar::new( "https://avatars.githubusercontent.com/u/1714999?v=4", diff --git a/crates/ui2/src/components/button.rs b/crates/ui2/src/components/button.rs index d7d526b087..c70c6981fa 100644 --- a/crates/ui2/src/components/button.rs +++ b/crates/ui2/src/components/button.rs @@ -1,8 +1,8 @@ -use std::sync::Arc; +use std::rc::Rc; use gpui::{ - DefiniteLength, DefiniteLength, Div, Hsla, MouseButton, RenderOnce, Stateful, - StatefulInteractiveElement, WindowContext, + DefiniteLength, Div, Hsla, MouseButton, MouseDownEvent, RenderOnce, StatefulInteractiveElement, + WindowContext, }; use crate::prelude::*; @@ -64,9 +64,10 @@ impl ButtonVariant { } } +#[derive(RenderOnce)] pub struct Button { disabled: bool, - click_handler: Option>, + click_handler: Option>, icon: Option, icon_position: Option, label: SharedString, @@ -75,10 +76,10 @@ pub struct Button { color: Option, } -impl RenderOnce for Button { - type Element = Stateful
; +impl Component for Button { + type Rendered = gpui::Stateful
; - fn render(self) -> Self::Rendered { + fn render(self, cx: &mut WindowContext) -> Self::Rendered { let (icon_color, label_color) = match (self.disabled, self.color) { (true, _) => (TextColor::Disabled, TextColor::Disabled), (_, None) => (TextColor::Default, TextColor::Default), @@ -116,9 +117,9 @@ impl RenderOnce for Button { button = button.w(width).justify_center(); } - if let Some(click_handler) = self.handlers.click.clone() { - button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| { - click_handler(state, cx); + if let Some(click_handler) = self.click_handler.clone() { + button = button.on_mouse_down(MouseButton::Left, move |event, cx| { + click_handler(event, cx); }); } @@ -167,8 +168,11 @@ impl Button { self } - pub fn on_click(mut self, handler: CallbackHandle<()>) -> Self { - self.handlers.click = Some(handler); + pub fn on_click( + mut self, + handler: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static, + ) -> Self { + self.click_handler = Some(Rc::new(handler)); self } @@ -215,15 +219,15 @@ impl Component for ButtonGroup { let mut group = h_stack(); for button in self.buttons.into_iter() { - group = group.child(button.render(view, cx)); + group = group.child(button.render(cx)); } group } } -impl ButtonGroup { - pub fn new(buttons: Vec>) -> Self { +impl ButtonGroup { + pub fn new(buttons: Vec