From 06bff418183ced84e9b6315874e4d68e25fa8207 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 25 Oct 2023 21:08:34 +0200 Subject: [PATCH 01/24] WIP: ElementRenderer --- crates/ui2/src/components/panes.rs | 80 +++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index 77b6817d89..e44056138b 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -12,7 +12,7 @@ pub enum SplitDirection { Vertical, } -#[derive(Element)] +// #[derive(Element)] pub struct Pane { id: ElementId, state_type: PhantomData, @@ -21,6 +21,84 @@ pub struct Pane { children: SmallVec<[AnyElement; 2]>, } +impl IntoAnyElement for Pane { + fn into_any(self) -> AnyElement { + ElementRenderer { + id: Some(self.id), + render: Some(move |view_state, cx| self.render(view_state, cx)), + view_type: PhantomData, + element_type: PhantomData, + } + } +} + +struct ElementRenderer +where + E: IntoAnyElement, + F: FnOnce(&mut V, &mut ViewContext) -> E, +{ + id: Option, + render: Option, + view_type: PhantomData, + element_type: PhantomData, +} + +impl Element for ElementRenderer +where + V: 'static, + E: IntoAnyElement, + F: FnOnce(&mut V, &mut ViewContext) -> E, +{ + type ViewState = V; + type ElementState = AnyElement; + + fn id(&self) -> Option { + self.id + } + + fn initialize( + &mut self, + view_state: &mut Self::ViewState, + rendered_element: Option, + cx: &mut ViewContext, + ) -> Self::ElementState { + rendered_element.unwrap_or_else(|| { + let render = self.render.take().unwrap(); + (render)(view_state, cx) + }) + } + + fn layout( + &mut self, + view_state: &mut Self::ViewState, + rendered_element: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> gpui2::LayoutId { + rendered_element.layout(view_state, cx) + } + + fn paint( + &mut self, + bounds: gpui2::Bounds, + view_state: &mut Self::ViewState, + rendered_element: &mut Self::ElementState, + cx: &mut ViewContext, + ) { + rendered_element.paint(view_state, cx) + } +} + +impl IntoAnyElement for ElementRenderer +where + V: 'static, + E: IntoAnyElement, + F: FnOnce(&mut V, &mut ViewContext) -> E, +{ + fn into_any(self) -> AnyElement { + self + } +} + impl Pane { pub fn new(id: impl Into, size: Size) -> Self { // Fill is only here for debugging purposes, remove before release From 965bfd8439f0c665e1e95a962f4ee0450a840585 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 26 Oct 2023 09:45:26 +0200 Subject: [PATCH 02/24] WIP: Pass in `V` to `Element` --- crates/gpui2/src/element.rs | 46 +++++++++---------- crates/gpui2/src/elements/div.rs | 25 +++++----- crates/gpui2/src/elements/img.rs | 13 +++--- crates/gpui2/src/elements/svg.rs | 15 +++--- crates/gpui2/src/focusable.rs | 19 ++------ crates/gpui2/src/interactive.rs | 79 +++++++++----------------------- crates/gpui2/src/view.rs | 33 ++++++------- 7 files changed, 87 insertions(+), 143 deletions(-) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index a6efbe52eb..e20d26b3d7 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -3,36 +3,35 @@ use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; use std::{any::Any, mem}; -pub trait Element: IntoAnyElement { - type ViewState: 'static; +pub trait Element: IntoAnyElement { type ElementState: 'static; fn id(&self) -> Option; fn initialize( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::ElementState; // where - // Self::ViewState: Any + Send + Sync; + // V: Any + Send + Sync; fn layout( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId; // where - // Self::ViewState: Any + Send + Sync; + // V: Any + Send + Sync; fn paint( &mut self, bounds: Bounds, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ); // where @@ -42,10 +41,10 @@ pub trait Element: IntoAnyElement { #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)] pub struct GlobalElementId(SmallVec<[ElementId; 32]>); -pub trait ParentElement: Element { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; +pub trait ParentElement: Element { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; - fn child(mut self, child: impl IntoAnyElement) -> Self + fn child(mut self, child: impl IntoAnyElement) -> Self where Self: Sized, { @@ -53,10 +52,7 @@ pub trait ParentElement: Element { self } - fn children( - mut self, - iter: impl IntoIterator>, - ) -> Self + fn children(mut self, iter: impl IntoIterator>) -> Self where Self: Sized, { @@ -72,7 +68,7 @@ trait ElementObject { fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext); } -struct RenderedElement { +struct RenderedElement> { element: E, phase: ElementRenderPhase, } @@ -94,7 +90,7 @@ enum ElementRenderPhase { /// Internal struct that wraps an element to store Layout and ElementState after the element is rendered. /// It's allocated as a trait object to erase the element type and wrapped in AnyElement for /// improved usability. -impl RenderedElement { +impl> RenderedElement { fn new(element: E) -> Self { RenderedElement { element, @@ -103,13 +99,13 @@ impl RenderedElement { } } -impl ElementObject for RenderedElement +impl ElementObject for RenderedElement where - E: Element, + E: Element, // E::ViewState: Any + Send + Sync, E::ElementState: Any + Send + Sync, { - fn initialize(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext) { + fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext) { let frame_state = if let Some(id) = self.element.id() { cx.with_element_state(id, |element_state, cx| { let element_state = self.element.initialize(view_state, element_state, cx); @@ -124,7 +120,7 @@ where self.phase = ElementRenderPhase::Initialized { frame_state }; } - fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext) -> LayoutId { + fn layout(&mut self, state: &mut V, cx: &mut ViewContext) -> LayoutId { let layout_id; let mut frame_state; match mem::take(&mut self.phase) { @@ -154,7 +150,7 @@ where layout_id } - fn paint(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext) { + fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext) { self.phase = match mem::take(&mut self.phase) { ElementRenderPhase::LayoutRequested { layout_id, @@ -186,7 +182,7 @@ impl AnyElement { pub fn new(element: E) -> Self where E: 'static + Send + Sync, - E: Element, + E: Element, E::ElementState: Any + Send + Sync, { AnyElement(Box::new(RenderedElement::new(element))) diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 71196eadca..9e1414e91a 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -189,12 +189,11 @@ pub struct DivState { child_layout_ids: SmallVec<[LayoutId; 4]>, } -impl Element for Div +impl Element for Div where I: ElementInteraction, F: ElementFocus, { - type ViewState = V; type ElementState = DivState; fn id(&self) -> Option { @@ -205,9 +204,9 @@ where fn initialize( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::ElementState { let mut element_state = element_state.unwrap_or_default(); self.focus @@ -224,9 +223,9 @@ where fn layout( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId { let style = self.compute_style(Bounds::default(), element_state, cx); style.apply_text_style(cx, |cx| { @@ -245,9 +244,9 @@ where fn paint( &mut self, bounds: Bounds, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { self.with_element_id(cx, |this, _global_id, cx| { if let Some(group) = this.group.clone() { @@ -315,12 +314,12 @@ where } } -impl ParentElement for Div +impl ParentElement for Div where I: ElementInteraction, F: ElementFocus, { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } @@ -335,7 +334,7 @@ where } } -impl StatelessInteractive for Div +impl StatelessInteractive for Div where I: ElementInteraction, F: ElementFocus, @@ -345,11 +344,11 @@ where } } -impl StatefulInteractive for Div, F> +impl StatefulInteractive for Div, F> where F: ElementFocus, { - fn stateful_interaction(&mut self) -> &mut StatefulInteraction { + fn stateful_interaction(&mut self) -> &mut StatefulInteraction { &mut self.interaction } } diff --git a/crates/gpui2/src/elements/img.rs b/crates/gpui2/src/elements/img.rs index adce6aea6b..e52b1ca332 100644 --- a/crates/gpui2/src/elements/img.rs +++ b/crates/gpui2/src/elements/img.rs @@ -65,12 +65,11 @@ where } } -impl Element for Img +impl Element for Img where I: ElementInteraction, F: ElementFocus, { - type ViewState = V; type ElementState = DivState; fn id(&self) -> Option { @@ -90,7 +89,7 @@ where &mut self, view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId { self.base.layout(view_state, element_state, cx) } @@ -143,7 +142,7 @@ where } } -impl StatelessInteractive for Img +impl StatelessInteractive for Img where I: ElementInteraction, F: ElementFocus, @@ -153,11 +152,11 @@ where } } -impl StatefulInteractive for Img, F> +impl StatefulInteractive for Img, F> where F: ElementFocus, { - fn stateful_interaction(&mut self) -> &mut StatefulInteraction { + fn stateful_interaction(&mut self) -> &mut StatefulInteraction { self.base.stateful_interaction() } } @@ -167,7 +166,7 @@ where V: 'static, I: ElementInteraction, { - fn focus_listeners(&mut self) -> &mut FocusListeners { + fn focus_listeners(&mut self) -> &mut FocusListeners { self.base.focus_listeners() } diff --git a/crates/gpui2/src/elements/svg.rs b/crates/gpui2/src/elements/svg.rs index 7e9017264f..ae388efb3f 100644 --- a/crates/gpui2/src/elements/svg.rs +++ b/crates/gpui2/src/elements/svg.rs @@ -55,12 +55,11 @@ where } } -impl Element for Svg +impl Element for Svg where I: ElementInteraction, F: ElementFocus, { - type ViewState = V; type ElementState = DivState; fn id(&self) -> Option { @@ -80,7 +79,7 @@ where &mut self, view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId { self.base.layout(view_state, element_state, cx) } @@ -88,7 +87,7 @@ where fn paint( &mut self, bounds: Bounds, - view: &mut Self::ViewState, + view: &mut V, element_state: &mut Self::ElementState, cx: &mut ViewContext, ) where @@ -116,7 +115,7 @@ where } } -impl StatelessInteractive for Svg +impl StatelessInteractive for Svg where I: ElementInteraction, F: ElementFocus, @@ -126,12 +125,12 @@ where } } -impl StatefulInteractive for Svg, F> +impl StatefulInteractive for Svg, F> where V: 'static, F: ElementFocus, { - fn stateful_interaction(&mut self) -> &mut StatefulInteraction { + fn stateful_interaction(&mut self) -> &mut StatefulInteraction { self.base.stateful_interaction() } } @@ -140,7 +139,7 @@ impl Focusable for Svg> where I: ElementInteraction, { - fn focus_listeners(&mut self) -> &mut FocusListeners { + fn focus_listeners(&mut self) -> &mut FocusListeners { self.base.focus_listeners() } diff --git a/crates/gpui2/src/focusable.rs b/crates/gpui2/src/focusable.rs index 3345b4c6c6..0d2e09ec49 100644 --- a/crates/gpui2/src/focusable.rs +++ b/crates/gpui2/src/focusable.rs @@ -11,8 +11,8 @@ pub type FocusListeners = SmallVec<[FocusListener; 2]>; pub type FocusListener = Arc) + Send + Sync + 'static>; -pub trait Focusable: Element { - fn focus_listeners(&mut self) -> &mut FocusListeners; +pub trait Focusable: Element { + fn focus_listeners(&mut self) -> &mut FocusListeners; fn set_focus_style(&mut self, style: StyleRefinement); fn set_focus_in_style(&mut self, style: StyleRefinement); fn set_in_focus_style(&mut self, style: StyleRefinement); @@ -62,10 +62,7 @@ pub trait Focusable: Element { fn on_blur( mut self, - listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -81,10 +78,7 @@ pub trait Focusable: Element { fn on_focus_in( mut self, - listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -109,10 +103,7 @@ pub trait Focusable: Element { fn on_focus_out( mut self, - listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index fd603eda46..7cc014e723 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -19,8 +19,8 @@ use std::{ const DRAG_THRESHOLD: f64 = 2.; -pub trait StatelessInteractive: Element { - fn stateless_interaction(&mut self) -> &mut StatelessInteraction; +pub trait StatelessInteractive: Element { + fn stateless_interaction(&mut self) -> &mut StatelessInteraction; fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self where @@ -48,10 +48,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_down( mut self, button: MouseButton, - handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -72,10 +69,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_up( mut self, button: MouseButton, - handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -96,10 +90,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_down_out( mut self, button: MouseButton, - handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -120,10 +111,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_up_out( mut self, button: MouseButton, - handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -143,10 +131,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_move( mut self, - handler: impl Fn(&mut Self::ViewState, &MouseMoveEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -163,10 +148,7 @@ pub trait StatelessInteractive: Element { fn on_scroll_wheel( mut self, - handler: impl Fn(&mut Self::ViewState, &ScrollWheelEvent, &mut ViewContext) - + Send - + Sync - + 'static, + handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -194,10 +176,7 @@ pub trait StatelessInteractive: Element { fn on_action( mut self, - listener: impl Fn(&mut Self::ViewState, &A, DispatchPhase, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &A, DispatchPhase, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -215,12 +194,8 @@ pub trait StatelessInteractive: Element { fn on_key_down( mut self, - listener: impl Fn( - &mut Self::ViewState, - &KeyDownEvent, - DispatchPhase, - &mut ViewContext, - ) + Send + listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext) + + Send + Sync + 'static, ) -> Self @@ -240,7 +215,7 @@ pub trait StatelessInteractive: Element { fn on_key_up( mut self, - listener: impl Fn(&mut Self::ViewState, &KeyUpEvent, DispatchPhase, &mut ViewContext) + listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext) + Send + Sync + 'static, @@ -289,10 +264,7 @@ pub trait StatelessInteractive: Element { fn on_drop( mut self, - listener: impl Fn(&mut Self::ViewState, S, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, S, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -307,8 +279,8 @@ pub trait StatelessInteractive: Element { } } -pub trait StatefulInteractive: StatelessInteractive { - fn stateful_interaction(&mut self) -> &mut StatefulInteraction; +pub trait StatefulInteractive: StatelessInteractive { + fn stateful_interaction(&mut self) -> &mut StatefulInteraction; fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self where @@ -335,10 +307,7 @@ pub trait StatefulInteractive: StatelessInteractive { fn on_click( mut self, - listener: impl Fn(&mut Self::ViewState, &ClickEvent, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, @@ -351,20 +320,14 @@ pub trait StatefulInteractive: StatelessInteractive { fn on_drag( mut self, - listener: impl Fn( - &mut Self::ViewState, - &mut ViewContext, - ) -> Drag - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &mut ViewContext) -> Drag + Send + Sync + 'static, ) -> Self where Self: Sized, S: Any + Send + Sync, - R: Fn(&mut Self::ViewState, &mut ViewContext) -> E, + R: Fn(&mut V, &mut ViewContext) -> E, R: 'static + Send + Sync, - E: Element, + E: Element, { debug_assert!( self.stateful_interaction().drag_listener.is_none(), @@ -907,7 +870,7 @@ pub struct ClickEvent { pub struct Drag where R: Fn(&mut V, &mut ViewContext) -> E, - E: Element, + E: Element, { pub state: S, pub render_drag_handle: R, @@ -917,7 +880,7 @@ where impl Drag where R: Fn(&mut V, &mut ViewContext) -> E, - E: Element, + E: Element, { pub fn new(state: S, render_drag_handle: R) -> Self { Drag { diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index ed633e8966..13f29e641d 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -50,8 +50,7 @@ impl IntoAnyElement for V } } -impl Element for View { - type ViewState = (); +impl Element<()> for View { type ElementState = AnyElement; fn id(&self) -> Option { @@ -105,8 +104,7 @@ impl IntoAnyElement for EraseViewState Element for EraseViewState { - type ViewState = ParentV; +impl Element for EraseViewState { type ElementState = AnyBox; fn id(&self) -> Option { @@ -115,18 +113,18 @@ impl Element for EraseViewState { fn initialize( &mut self, - _: &mut Self::ViewState, + _: &mut ParentV, _: Option, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::ElementState { ViewObject::initialize(&mut self.view, cx) } fn layout( &mut self, - _: &mut Self::ViewState, + _: &mut ParentV, element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId { ViewObject::layout(&mut self.view, element, cx) } @@ -134,9 +132,9 @@ impl Element for EraseViewState { fn paint( &mut self, bounds: Bounds, - _: &mut Self::ViewState, + _: &mut ParentV, element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { ViewObject::paint(&mut self.view, bounds, element, cx) } @@ -247,8 +245,7 @@ impl IntoAnyElement for EraseAnyViewState { } } -impl Element for EraseAnyViewState { - type ViewState = ParentV; +impl Element for EraseAnyViewState { type ElementState = AnyBox; fn id(&self) -> Option { @@ -257,18 +254,18 @@ impl Element for EraseAnyViewState { fn initialize( &mut self, - _: &mut Self::ViewState, + _: &mut ParentV, _: Option, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::ElementState { self.view.view.lock().initialize(cx) } fn layout( &mut self, - _: &mut Self::ViewState, + _: &mut ParentV, element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId { self.view.view.lock().layout(element, cx) } @@ -276,9 +273,9 @@ impl Element for EraseAnyViewState { fn paint( &mut self, bounds: Bounds, - _: &mut Self::ViewState, + _: &mut ParentV, element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { self.view.view.lock().paint(bounds, element, cx) } From 8b972f6d8ebbbf73955f26a3e77764a0a7be8c23 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 26 Oct 2023 09:51:33 +0200 Subject: [PATCH 03/24] WIP: Fix compilation of `gpui2` --- crates/gpui2/src/element.rs | 5 +++-- crates/gpui2/src/elements/div.rs | 2 +- crates/gpui2/src/elements/img.rs | 2 +- crates/gpui2/src/elements/svg.rs | 2 +- crates/gpui2/src/elements/text.rs | 3 +-- crates/gpui2/src/focusable.rs | 7 ++----- crates/gpui2/src/interactive.rs | 6 ++++-- crates/gpui2/src/view.rs | 13 ++++++------- 8 files changed, 19 insertions(+), 21 deletions(-) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index e20d26b3d7..c6707049a6 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -41,7 +41,7 @@ pub trait Element: IntoAnyElement { #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)] pub struct GlobalElementId(SmallVec<[ElementId; 32]>); -pub trait ParentElement: Element { +pub trait ParentElement: Element { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; fn child(mut self, child: impl IntoAnyElement) -> Self @@ -68,7 +68,7 @@ trait ElementObject { fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext); } -struct RenderedElement> { +struct RenderedElement> { element: E, phase: ElementRenderPhase, } @@ -181,6 +181,7 @@ pub struct AnyElement(Box + Send + Sync>); impl AnyElement { pub fn new(element: E) -> Self where + V: 'static, E: 'static + Send + Sync, E: Element, E::ElementState: Any + Send + Sync, diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 9e1414e91a..fbef75ab1c 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -160,7 +160,7 @@ impl Div, FocusDisabled> { } } -impl Focusable for Div> +impl Focusable for Div> where V: 'static, I: ElementInteraction, diff --git a/crates/gpui2/src/elements/img.rs b/crates/gpui2/src/elements/img.rs index e52b1ca332..d64536a7ed 100644 --- a/crates/gpui2/src/elements/img.rs +++ b/crates/gpui2/src/elements/img.rs @@ -161,7 +161,7 @@ where } } -impl Focusable for Img> +impl Focusable for Img> where V: 'static, I: ElementInteraction, diff --git a/crates/gpui2/src/elements/svg.rs b/crates/gpui2/src/elements/svg.rs index ae388efb3f..409094d740 100644 --- a/crates/gpui2/src/elements/svg.rs +++ b/crates/gpui2/src/elements/svg.rs @@ -135,7 +135,7 @@ where } } -impl Focusable for Svg> +impl Focusable for Svg> where I: ElementInteraction, { diff --git a/crates/gpui2/src/elements/text.rs b/crates/gpui2/src/elements/text.rs index 7b0052826c..e054da87a6 100644 --- a/crates/gpui2/src/elements/text.rs +++ b/crates/gpui2/src/elements/text.rs @@ -53,8 +53,7 @@ impl IntoAnyElement for Text { } } -impl Element for Text { - type ViewState = V; +impl Element for Text { type ElementState = Arc>>; fn id(&self) -> Option { diff --git a/crates/gpui2/src/focusable.rs b/crates/gpui2/src/focusable.rs index 0d2e09ec49..c283998ca2 100644 --- a/crates/gpui2/src/focusable.rs +++ b/crates/gpui2/src/focusable.rs @@ -11,7 +11,7 @@ pub type FocusListeners = SmallVec<[FocusListener; 2]>; pub type FocusListener = Arc) + Send + Sync + 'static>; -pub trait Focusable: Element { +pub trait Focusable: Element { fn focus_listeners(&mut self) -> &mut FocusListeners; fn set_focus_style(&mut self, style: StyleRefinement); fn set_focus_in_style(&mut self, style: StyleRefinement); @@ -43,10 +43,7 @@ pub trait Focusable: Element { fn on_focus( mut self, - listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext) - + Send - + Sync - + 'static, + listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index 7cc014e723..f00e24b472 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -19,7 +19,7 @@ use std::{ const DRAG_THRESHOLD: f64 = 2.; -pub trait StatelessInteractive: Element { +pub trait StatelessInteractive: Element { fn stateless_interaction(&mut self) -> &mut StatelessInteraction; fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self @@ -279,7 +279,7 @@ pub trait StatelessInteractive: Element { } } -pub trait StatefulInteractive: StatelessInteractive { +pub trait StatefulInteractive: StatelessInteractive { fn stateful_interaction(&mut self) -> &mut StatefulInteraction; fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self @@ -870,6 +870,7 @@ pub struct ClickEvent { pub struct Drag where R: Fn(&mut V, &mut ViewContext) -> E, + V: 'static, E: Element, { pub state: S, @@ -880,6 +881,7 @@ where impl Drag where R: Fn(&mut V, &mut ViewContext) -> E, + V: 'static, E: Element, { pub fn new(state: S, render_drag_handle: R) -> Self { diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index 13f29e641d..b1b287c4ab 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -194,8 +194,7 @@ impl IntoAnyElement for AnyView { } } -impl Element for AnyView { - type ViewState = (); +impl Element<()> for AnyView { type ElementState = AnyBox; fn id(&self) -> Option { @@ -204,18 +203,18 @@ impl Element for AnyView { fn initialize( &mut self, - _: &mut Self::ViewState, + _: &mut (), _: Option, - cx: &mut ViewContext, + cx: &mut ViewContext<()>, ) -> Self::ElementState { self.view.lock().initialize(cx) } fn layout( &mut self, - _: &mut Self::ViewState, + _: &mut (), element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext<()>, ) -> LayoutId { self.view.lock().layout(element, cx) } @@ -225,7 +224,7 @@ impl Element for AnyView { bounds: Bounds, _: &mut (), element: &mut AnyBox, - cx: &mut ViewContext, + cx: &mut ViewContext<()>, ) { self.view.lock().paint(bounds, element, cx) } From 9fb9885931091380d542f83b36d5c86ed69093c6 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 26 Oct 2023 10:08:39 +0200 Subject: [PATCH 04/24] Checkpoint: Compiling --- crates/gpui2_macros/src/derive_element.rs | 15 +++++----- crates/storybook2/src/stories/kitchen_sink.rs | 2 +- crates/storybook2/src/stories/scroll.rs | 2 +- crates/storybook2/src/stories/z_index.rs | 14 ++++----- crates/storybook2/src/storybook2.rs | 2 +- crates/ui2/src/components/assistant_panel.rs | 4 +-- crates/ui2/src/components/breadcrumb.rs | 4 +-- crates/ui2/src/components/buffer.rs | 8 ++--- crates/ui2/src/components/buffer_search.rs | 2 +- crates/ui2/src/components/chat_panel.rs | 6 ++-- crates/ui2/src/components/collab_panel.rs | 4 +-- crates/ui2/src/components/command_palette.rs | 4 +-- crates/ui2/src/components/context_menu.rs | 4 +-- crates/ui2/src/components/copilot.rs | 4 +-- crates/ui2/src/components/editor_pane.rs | 2 +- crates/ui2/src/components/facepile.rs | 4 +-- crates/ui2/src/components/icon_button.rs | 2 +- crates/ui2/src/components/keybinding.rs | 6 ++-- .../ui2/src/components/language_selector.rs | 4 +-- crates/ui2/src/components/list.rs | 16 +++++----- crates/ui2/src/components/modal.rs | 6 ++-- crates/ui2/src/components/multi_buffer.rs | 4 +-- .../ui2/src/components/notification_toast.rs | 2 +- .../ui2/src/components/notifications_panel.rs | 4 +-- crates/ui2/src/components/palette.rs | 6 ++-- crates/ui2/src/components/panel.rs | 8 ++--- crates/ui2/src/components/panes.rs | 8 ++--- crates/ui2/src/components/player_stack.rs | 2 +- crates/ui2/src/components/project_panel.rs | 4 +-- crates/ui2/src/components/recent_projects.rs | 4 +-- crates/ui2/src/components/status_bar.rs | 10 ++----- crates/ui2/src/components/tab.rs | 4 +-- crates/ui2/src/components/tab_bar.rs | 4 +-- crates/ui2/src/components/terminal.rs | 4 +-- crates/ui2/src/components/theme_selector.rs | 4 +-- crates/ui2/src/components/title_bar.rs | 4 +-- crates/ui2/src/components/toast.rs | 12 +++----- crates/ui2/src/components/toolbar.rs | 4 +-- crates/ui2/src/components/traffic_lights.rs | 6 ++-- crates/ui2/src/components/workspace.rs | 6 ++-- crates/ui2/src/element_ext.rs | 4 +-- crates/ui2/src/elements/avatar.rs | 4 +-- crates/ui2/src/elements/button.rs | 6 ++-- crates/ui2/src/elements/details.rs | 4 +-- crates/ui2/src/elements/icon.rs | 4 +-- crates/ui2/src/elements/input.rs | 4 +-- crates/ui2/src/elements/label.rs | 6 ++-- crates/ui2/src/elements/tool_divider.rs | 2 +- crates/ui2/src/story.rs | 6 ++-- crates/ui2/src/theme.rs | 30 ++++++++++--------- 50 files changed, 139 insertions(+), 146 deletions(-) diff --git a/crates/gpui2_macros/src/derive_element.rs b/crates/gpui2_macros/src/derive_element.rs index 3f6b053aa0..a63be0f5da 100644 --- a/crates/gpui2_macros/src/derive_element.rs +++ b/crates/gpui2_macros/src/derive_element.rs @@ -47,10 +47,9 @@ pub fn derive_element(input: TokenStream) -> TokenStream { } } - impl #impl_generics gpui2::Element for #type_name #ty_generics + impl #impl_generics gpui2::Element<#state_type> for #type_name #ty_generics #where_clause { - type ViewState = #state_type; type ElementState = gpui2::AnyElement<#state_type>; fn id(&self) -> Option { @@ -59,9 +58,9 @@ pub fn derive_element(input: TokenStream) -> TokenStream { fn initialize( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut #state_type, _: Option, - cx: &mut gpui2::ViewContext + cx: &mut gpui2::ViewContext<#state_type> ) -> Self::ElementState { use gpui2::IntoAnyElement; @@ -72,9 +71,9 @@ pub fn derive_element(input: TokenStream) -> TokenStream { fn layout( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut #state_type, rendered_element: &mut Self::ElementState, - cx: &mut gpui2::ViewContext, + cx: &mut gpui2::ViewContext<#state_type>, ) -> gpui2::LayoutId { rendered_element.layout(view_state, cx) } @@ -82,9 +81,9 @@ pub fn derive_element(input: TokenStream) -> TokenStream { fn paint( &mut self, bounds: gpui2::Bounds, - view_state: &mut Self::ViewState, + view_state: &mut #state_type, rendered_element: &mut Self::ElementState, - cx: &mut gpui2::ViewContext, + cx: &mut gpui2::ViewContext<#state_type>, ) { rendered_element.paint(view_state, cx) } diff --git a/crates/storybook2/src/stories/kitchen_sink.rs b/crates/storybook2/src/stories/kitchen_sink.rs index e7c4e752f6..63cb1d0f51 100644 --- a/crates/storybook2/src/stories/kitchen_sink.rs +++ b/crates/storybook2/src/stories/kitchen_sink.rs @@ -16,7 +16,7 @@ impl KitchenSinkStory { view(cx.entity(|cx| Self::new()), Self::render) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl Element { let element_stories = ElementStory::iter() .map(|selector| selector.story(cx)) .collect::>(); diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs index c5df3bd3d3..67200b52bc 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -16,7 +16,7 @@ impl ScrollStory { } } -fn checkerboard(depth: usize) -> impl Element +fn checkerboard(depth: usize) -> impl Element where S: 'static + Send + Sync, { diff --git a/crates/storybook2/src/stories/z_index.rs b/crates/storybook2/src/stories/z_index.rs index 9dd74b6884..39ac6fd6e4 100644 --- a/crates/storybook2/src/stories/z_index.rs +++ b/crates/storybook2/src/stories/z_index.rs @@ -19,7 +19,7 @@ impl ZIndexStory { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { Story::container(cx) .child(Story::title(cx, "z-index")) .child( @@ -86,23 +86,23 @@ trait Styles: Styled + Sized { } } -impl Styles for Div {} +impl Styles for Div {} #[derive(Element)] -struct ZIndexExample { - state_type: PhantomData, +struct ZIndexExample { + view_type: PhantomData, z_index: u32, } -impl ZIndexExample { +impl ZIndexExample { pub fn new(z_index: u32) -> Self { Self { - state_type: PhantomData, + view_type: PhantomData, z_index, } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut V, cx: &mut ViewContext) -> impl Element { div() .relative() .size_full() diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index c6d71f079d..107d737ef9 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -107,7 +107,7 @@ impl StoryWrapper { Self { story, theme } } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl Element { themed(self.theme.clone(), cx, |cx| { div() .flex() diff --git a/crates/ui2/src/components/assistant_panel.rs b/crates/ui2/src/components/assistant_panel.rs index 31f299de91..77d29f44f7 100644 --- a/crates/ui2/src/components/assistant_panel.rs +++ b/crates/ui2/src/components/assistant_panel.rs @@ -26,7 +26,7 @@ impl AssistantPanel { self } - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { Panel::new(self.id.clone(), cx) .children(vec![div() .flex() @@ -100,7 +100,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, AssistantPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/breadcrumb.rs b/crates/ui2/src/components/breadcrumb.rs index e67ceb1751..4bd5283db3 100644 --- a/crates/ui2/src/components/breadcrumb.rs +++ b/crates/ui2/src/components/breadcrumb.rs @@ -35,7 +35,7 @@ impl Breadcrumb { &mut self, view_state: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let theme = theme(cx); let symbols_len = self.symbols.len(); @@ -106,7 +106,7 @@ mod stories { &mut self, view_state: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer.rs b/crates/ui2/src/components/buffer.rs index 2e0e07e16c..51f5ea9196 100644 --- a/crates/ui2/src/components/buffer.rs +++ b/crates/ui2/src/components/buffer.rs @@ -158,7 +158,7 @@ impl Buffer { self } - fn render_row(row: BufferRow, cx: &WindowContext) -> impl Element { + fn render_row(row: BufferRow, cx: &WindowContext) -> impl Element { let theme = theme(cx); let line_background = if row.current { @@ -208,7 +208,7 @@ impl Buffer { })) } - fn render_rows(&self, cx: &WindowContext) -> Vec> { + fn render_rows(&self, cx: &WindowContext) -> Vec> { match &self.rows { Some(rows) => rows .rows @@ -219,7 +219,7 @@ impl Buffer { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let rows = self.render_rows(cx); @@ -262,7 +262,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer_search.rs b/crates/ui2/src/components/buffer_search.rs index 1edbd58c87..3294aec780 100644 --- a/crates/ui2/src/components/buffer_search.rs +++ b/crates/ui2/src/components/buffer_search.rs @@ -25,7 +25,7 @@ impl BufferSearch { view(cx.entity(|cx| Self::new()), Self::render) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); h_stack().bg(theme.toolbar).p_2().child( diff --git a/crates/ui2/src/components/chat_panel.rs b/crates/ui2/src/components/chat_panel.rs index 7afccd6d9d..b66868138f 100644 --- a/crates/ui2/src/components/chat_panel.rs +++ b/crates/ui2/src/components/chat_panel.rs @@ -24,7 +24,7 @@ impl ChatPanel { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div() .id(self.element_id.clone()) .flex() @@ -88,7 +88,7 @@ impl ChatMessage { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div() .flex() .flex_col() @@ -133,7 +133,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, ChatPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/collab_panel.rs b/crates/ui2/src/components/collab_panel.rs index 6414e0e5ff..40276f20b3 100644 --- a/crates/ui2/src/components/collab_panel.rs +++ b/crates/ui2/src/components/collab_panel.rs @@ -19,7 +19,7 @@ impl CollabPanel { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); v_stack() @@ -114,7 +114,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, CollabPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/command_palette.rs b/crates/ui2/src/components/command_palette.rs index 45194e843c..036a41e0b9 100644 --- a/crates/ui2/src/components/command_palette.rs +++ b/crates/ui2/src/components/command_palette.rs @@ -17,7 +17,7 @@ impl CommandPalette { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div().id(self.id.clone()).child( Palette::new("palette") .items(example_editor_actions()) @@ -53,7 +53,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, CommandPalette>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 73813ed613..fb076dc9fe 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -42,7 +42,7 @@ impl ContextMenu { items: items.into_iter().collect(), } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); v_stack() @@ -89,7 +89,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, ContextMenu>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/copilot.rs b/crates/ui2/src/components/copilot.rs index b0f20cfa0d..8c51b1f4eb 100644 --- a/crates/ui2/src/components/copilot.rs +++ b/crates/ui2/src/components/copilot.rs @@ -16,7 +16,7 @@ impl CopilotModal { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div().id(self.id.clone()).child( Modal::new("some-id") .title("Connect Copilot to Zed") @@ -51,7 +51,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, CopilotModal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/editor_pane.rs b/crates/ui2/src/components/editor_pane.rs index 7489b3e47d..b641c86f7e 100644 --- a/crates/ui2/src/components/editor_pane.rs +++ b/crates/ui2/src/components/editor_pane.rs @@ -49,7 +49,7 @@ impl EditorPane { ) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl Element { v_stack() .w_full() .h_full() diff --git a/crates/ui2/src/components/facepile.rs b/crates/ui2/src/components/facepile.rs index 9a96d80010..b75ef328f3 100644 --- a/crates/ui2/src/components/facepile.rs +++ b/crates/ui2/src/components/facepile.rs @@ -17,7 +17,7 @@ impl Facepile { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let player_count = self.players.len(); let player_list = self.players.iter().enumerate().map(|(ix, player)| { let isnt_last = ix < player_count - 1; @@ -55,7 +55,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let players = static_players(); Story::container(cx) diff --git a/crates/ui2/src/components/icon_button.rs b/crates/ui2/src/components/icon_button.rs index b74165720d..77d248e9ee 100644 --- a/crates/ui2/src/components/icon_button.rs +++ b/crates/ui2/src/components/icon_button.rs @@ -68,7 +68,7 @@ impl IconButton { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let icon_color = match (self.state, self.color) { diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index 2fb40adac6..25de760cab 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -34,7 +34,7 @@ impl Keybinding { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div() .flex() .gap_2() @@ -68,7 +68,7 @@ impl Key { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div() @@ -189,7 +189,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let all_modifier_permutations = ModifierKey::iter().permutations(2); Story::container(cx) diff --git a/crates/ui2/src/components/language_selector.rs b/crates/ui2/src/components/language_selector.rs index 224db69754..dbead8467e 100644 --- a/crates/ui2/src/components/language_selector.rs +++ b/crates/ui2/src/components/language_selector.rs @@ -17,7 +17,7 @@ impl LanguageSelector { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div().id(self.id.clone()).child( Palette::new("palette") .items(vec![ @@ -64,7 +64,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, LanguageSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index 99282fa06d..0c41671247 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -92,7 +92,7 @@ impl ListHeader { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let is_toggleable = self.toggleable != Toggleable::NotToggleable; @@ -157,7 +157,7 @@ impl ListSubHeader { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { h_stack().flex_1().w_full().relative().py_1().child( div() .h_6() @@ -230,7 +230,7 @@ impl From> for ListItem { } impl ListItem { - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { match self { ListItem::Entry(entry) => div().child(entry.render(view, cx)), ListItem::Separator(separator) => div().child(separator.render(view, cx)), @@ -347,7 +347,7 @@ impl ListEntry { fn disclosure_control( &mut self, cx: &mut ViewContext, - ) -> Option> { + ) -> Option> { let disclosure_control_icon = if let Some(ToggleState::Toggled) = self.toggle { IconElement::new(Icon::ChevronDown) } else { @@ -367,7 +367,7 @@ impl ListEntry { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let settings = user_settings(cx); let theme = theme(cx); @@ -477,7 +477,7 @@ impl ListDetailsEntry { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let settings = user_settings(cx); @@ -534,7 +534,7 @@ impl ListSeparator { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div().h_px().w_full().bg(theme.border) @@ -574,7 +574,7 @@ impl List { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let is_toggleable = self.toggleable != Toggleable::NotToggleable; let is_toggled = Toggleable::is_toggled(&self.toggleable); diff --git a/crates/ui2/src/components/modal.rs b/crates/ui2/src/components/modal.rs index 792f8e1268..154df4e862 100644 --- a/crates/ui2/src/components/modal.rs +++ b/crates/ui2/src/components/modal.rs @@ -42,7 +42,7 @@ impl Modal { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); v_stack() @@ -80,8 +80,8 @@ impl Modal { } } -impl ParentElement for Modal { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { +impl ParentElement for Modal { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } diff --git a/crates/ui2/src/components/multi_buffer.rs b/crates/ui2/src/components/multi_buffer.rs index b53ea13ef2..568302b559 100644 --- a/crates/ui2/src/components/multi_buffer.rs +++ b/crates/ui2/src/components/multi_buffer.rs @@ -17,7 +17,7 @@ impl MultiBuffer { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); v_stack() @@ -66,7 +66,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/notification_toast.rs b/crates/ui2/src/components/notification_toast.rs index b7709e1a58..afcef8fb20 100644 --- a/crates/ui2/src/components/notification_toast.rs +++ b/crates/ui2/src/components/notification_toast.rs @@ -28,7 +28,7 @@ impl NotificationToast { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); h_stack() diff --git a/crates/ui2/src/components/notifications_panel.rs b/crates/ui2/src/components/notifications_panel.rs index eaf64eb484..fd0445d007 100644 --- a/crates/ui2/src/components/notifications_panel.rs +++ b/crates/ui2/src/components/notifications_panel.rs @@ -17,7 +17,7 @@ impl NotificationsPanel { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div() @@ -74,7 +74,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, NotificationsPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/palette.rs b/crates/ui2/src/components/palette.rs index 87eb88c764..9787086cd6 100644 --- a/crates/ui2/src/components/palette.rs +++ b/crates/ui2/src/components/palette.rs @@ -46,7 +46,7 @@ impl Palette { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); v_stack() @@ -135,7 +135,7 @@ impl PaletteItem { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div() .flex() .flex_row() @@ -176,7 +176,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, Palette>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index 90dbcf3959..0c52a7a12a 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -96,7 +96,7 @@ impl Panel { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let current_size = self.width.unwrap_or(self.initial_width); @@ -121,8 +121,8 @@ impl Panel { } } -impl ParentElement for Panel { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { +impl ParentElement for Panel { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } @@ -152,7 +152,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, Panel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index 77b6817d89..fd95853201 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -40,7 +40,7 @@ impl Pane { self } - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { div() .id(self.id.clone()) .flex() @@ -70,8 +70,8 @@ impl Pane { } } -impl ParentElement for Pane { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { +impl ParentElement for Pane { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } @@ -103,7 +103,7 @@ impl PaneGroup { } } - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); if !self.panes.is_empty() { diff --git a/crates/ui2/src/components/player_stack.rs b/crates/ui2/src/components/player_stack.rs index 0240af8f47..0ada98aa3f 100644 --- a/crates/ui2/src/components/player_stack.rs +++ b/crates/ui2/src/components/player_stack.rs @@ -17,7 +17,7 @@ impl PlayerStack { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let player = self.player_with_call_status.get_player(); self.player_with_call_status.get_call_status(); diff --git a/crates/ui2/src/components/project_panel.rs b/crates/ui2/src/components/project_panel.rs index 9328b21d43..8b52a1b89a 100644 --- a/crates/ui2/src/components/project_panel.rs +++ b/crates/ui2/src/components/project_panel.rs @@ -19,7 +19,7 @@ impl ProjectPanel { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div() @@ -83,7 +83,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, ProjectPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/recent_projects.rs b/crates/ui2/src/components/recent_projects.rs index 6a5f570562..16c019be53 100644 --- a/crates/ui2/src/components/recent_projects.rs +++ b/crates/ui2/src/components/recent_projects.rs @@ -17,7 +17,7 @@ impl RecentProjects { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div().id(self.id.clone()).child( Palette::new("palette") .items(vec![ @@ -60,7 +60,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, RecentProjects>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/status_bar.rs b/crates/ui2/src/components/status_bar.rs index db28ac5070..5eeeb841ef 100644 --- a/crates/ui2/src/components/status_bar.rs +++ b/crates/ui2/src/components/status_bar.rs @@ -86,7 +86,7 @@ impl StatusBar { &mut self, view: &mut Workspace, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let theme = theme(cx); div() @@ -101,11 +101,7 @@ impl StatusBar { .child(self.right_tools(view, cx)) } - fn left_tools( - &self, - workspace: &mut Workspace, - cx: &WindowContext, - ) -> impl Element { + fn left_tools(&self, workspace: &mut Workspace, cx: &WindowContext) -> impl Element { div() .flex() .items_center() @@ -136,7 +132,7 @@ impl StatusBar { &self, workspace: &mut Workspace, cx: &WindowContext, - ) -> impl Element { + ) -> impl Element { div() .flex() .items_center() diff --git a/crates/ui2/src/components/tab.rs b/crates/ui2/src/components/tab.rs index 451dba9aa4..4bfd21248f 100644 --- a/crates/ui2/src/components/tab.rs +++ b/crates/ui2/src/components/tab.rs @@ -81,7 +81,7 @@ impl Tab { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict; let is_deleted = self.fs_status == FileSystemStatus::Deleted; @@ -192,7 +192,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let git_statuses = GitStatus::iter(); let fs_statuses = FileSystemStatus::iter(); diff --git a/crates/ui2/src/components/tab_bar.rs b/crates/ui2/src/components/tab_bar.rs index ef67088287..0cc9409c04 100644 --- a/crates/ui2/src/components/tab_bar.rs +++ b/crates/ui2/src/components/tab_bar.rs @@ -27,7 +27,7 @@ impl TabBar { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let (can_navigate_back, can_navigate_forward) = self.can_navigate; @@ -116,7 +116,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, TabBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/terminal.rs b/crates/ui2/src/components/terminal.rs index 236a8961bb..480c1a5da6 100644 --- a/crates/ui2/src/components/terminal.rs +++ b/crates/ui2/src/components/terminal.rs @@ -17,7 +17,7 @@ impl Terminal { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let can_navigate_back = true; @@ -109,7 +109,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, Terminal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/theme_selector.rs b/crates/ui2/src/components/theme_selector.rs index 3186e814bd..cb1b491d87 100644 --- a/crates/ui2/src/components/theme_selector.rs +++ b/crates/ui2/src/components/theme_selector.rs @@ -17,7 +17,7 @@ impl ThemeSelector { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div().child( Palette::new(self.id.clone()) .items(vec![ @@ -65,7 +65,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, ThemeSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/title_bar.rs b/crates/ui2/src/components/title_bar.rs index 4cfb092169..68661d0ea2 100644 --- a/crates/ui2/src/components/title_bar.rs +++ b/crates/ui2/src/components/title_bar.rs @@ -87,7 +87,7 @@ impl TitleBar { ) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let settings = user_settings(cx); @@ -204,7 +204,7 @@ mod stories { ) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl Element { Story::container(cx) .child(Story::title_for::<_, TitleBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/toast.rs b/crates/ui2/src/components/toast.rs index f75f921841..9318b12eec 100644 --- a/crates/ui2/src/components/toast.rs +++ b/crates/ui2/src/components/toast.rs @@ -36,7 +36,7 @@ impl Toast { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let mut div = div(); @@ -61,8 +61,8 @@ impl Toast { } } -impl ParentElement for Toast { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { +impl ParentElement for Toast { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } @@ -90,11 +90,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { Story::container(cx) .child(Story::title_for::<_, Toast>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/toolbar.rs b/crates/ui2/src/components/toolbar.rs index 2dc5dbff2f..51ec6ee497 100644 --- a/crates/ui2/src/components/toolbar.rs +++ b/crates/ui2/src/components/toolbar.rs @@ -54,7 +54,7 @@ impl Toolbar { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div() @@ -96,7 +96,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/traffic_lights.rs b/crates/ui2/src/components/traffic_lights.rs index 254855bc3f..e875075942 100644 --- a/crates/ui2/src/components/traffic_lights.rs +++ b/crates/ui2/src/components/traffic_lights.rs @@ -25,7 +25,7 @@ impl TrafficLight { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let fill = match (self.window_has_focus, self.color) { @@ -58,7 +58,7 @@ impl TrafficLights { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div() .flex() .items_center() @@ -103,7 +103,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, TrafficLights>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index ee913cb693..92ea93ef02 100644 --- a/crates/ui2/src/components/workspace.rs +++ b/crates/ui2/src/components/workspace.rs @@ -3,13 +3,13 @@ use std::sync::Arc; use chrono::DateTime; use gpui2::{px, relative, rems, view, Context, Size, View}; -use crate::{prelude::*, NotificationsPanel}; use crate::{ - static_livestream, old_theme, user_settings_mut, v_stack, AssistantPanel, Button, ChatMessage, + old_theme, static_livestream, user_settings_mut, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel, CollabPanel, EditorPane, FakeSettings, Label, LanguageSelector, Pane, PaneGroup, Panel, PanelAllowedSides, PanelSide, ProjectPanel, SettingValue, SplitDirection, StatusBar, Terminal, TitleBar, Toast, ToastOrigin, }; +use crate::{prelude::*, NotificationsPanel}; #[derive(Clone)] pub struct Gpui2UiDebug { @@ -174,7 +174,7 @@ impl Workspace { view(cx.entity(|cx| Self::new(cx)), Self::render) } - pub fn render(&mut self, cx: &mut ViewContext) -> impl Element { + pub fn render(&mut self, cx: &mut ViewContext) -> impl Element { let theme = old_theme(cx).clone(); // HACK: This should happen inside of `debug_toggle_user_settings`, but diff --git a/crates/ui2/src/element_ext.rs b/crates/ui2/src/element_ext.rs index a6ad48e629..813f01dd24 100644 --- a/crates/ui2/src/element_ext.rs +++ b/crates/ui2/src/element_ext.rs @@ -1,6 +1,6 @@ use gpui2::Element; -pub trait ElementExt: Element { +pub trait ElementExt: Element { /// Applies a given function `then` to the current element if `condition` is true. /// This function is used to conditionally modify the element based on a given condition. /// If `condition` is false, it just returns the current element as it is. @@ -25,4 +25,4 @@ pub trait ElementExt: Element { // } } -impl> ElementExt for E {} +impl> ElementExt for E {} diff --git a/crates/ui2/src/elements/avatar.rs b/crates/ui2/src/elements/avatar.rs index 416a55a4f7..0bc1ccad22 100644 --- a/crates/ui2/src/elements/avatar.rs +++ b/crates/ui2/src/elements/avatar.rs @@ -25,7 +25,7 @@ impl Avatar { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let mut img = img(); @@ -67,7 +67,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, Avatar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index 9948c91999..363f70ddb4 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -154,7 +154,7 @@ impl Button { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let icon_color = self.icon_color(); let mut button = h_stack() @@ -211,7 +211,7 @@ impl ButtonGroup { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let mut el = h_stack().text_size(ui_size(cx, 1.)); for button in &mut self.buttons { @@ -250,7 +250,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let states = InteractionState::iter(); Story::container(cx) diff --git a/crates/ui2/src/elements/details.rs b/crates/ui2/src/elements/details.rs index 9a37fb0935..e7df25f6a3 100644 --- a/crates/ui2/src/elements/details.rs +++ b/crates/ui2/src/elements/details.rs @@ -30,7 +30,7 @@ impl Details { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); v_stack() @@ -70,7 +70,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, Details>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/icon.rs b/crates/ui2/src/elements/icon.rs index ebeed25ea8..d20f262fbc 100644 --- a/crates/ui2/src/elements/icon.rs +++ b/crates/ui2/src/elements/icon.rs @@ -176,7 +176,7 @@ impl IconElement { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let fill = self.color.color(cx); let svg_size = match self.size { IconSize::Small => ui_size(cx, 12. / 14.), @@ -218,7 +218,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { let icons = Icon::iter(); Story::container(cx) diff --git a/crates/ui2/src/elements/input.rs b/crates/ui2/src/elements/input.rs index af0e73c9eb..56d81a0831 100644 --- a/crates/ui2/src/elements/input.rs +++ b/crates/ui2/src/elements/input.rs @@ -60,7 +60,7 @@ impl Input { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let (input_bg, input_hover_bg, input_active_bg) = match self.variant { @@ -136,7 +136,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, Input>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/label.rs b/crates/ui2/src/elements/label.rs index 81219206a9..d29ab8a5ee 100644 --- a/crates/ui2/src/elements/label.rs +++ b/crates/ui2/src/elements/label.rs @@ -83,7 +83,7 @@ impl Label { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { div() .when(self.strikethrough, |this| { this.relative().child( @@ -135,7 +135,7 @@ impl HighlightedLabel { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); let highlight_color = theme.text_accent; @@ -227,7 +227,7 @@ mod stories { &mut self, _view: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, Label>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/tool_divider.rs b/crates/ui2/src/elements/tool_divider.rs index 68b97ccb03..46b790e6bb 100644 --- a/crates/ui2/src/elements/tool_divider.rs +++ b/crates/ui2/src/elements/tool_divider.rs @@ -14,7 +14,7 @@ impl ToolDivider { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div().w_px().h_3().bg(theme.border) diff --git a/crates/ui2/src/story.rs b/crates/ui2/src/story.rs index 7a5358dfed..9fc6a11f19 100644 --- a/crates/ui2/src/story.rs +++ b/crates/ui2/src/story.rs @@ -21,7 +21,7 @@ impl Story { pub fn title( cx: &mut ViewContext, title: &str, - ) -> impl Element { + ) -> impl Element { let theme = theme(cx); div() @@ -32,14 +32,14 @@ impl Story { pub fn title_for( cx: &mut ViewContext, - ) -> impl Element { + ) -> impl Element { Self::title(cx, std::any::type_name::()) } pub fn label( cx: &mut ViewContext, label: &str, - ) -> impl Element { + ) -> impl Element { let theme = theme(cx); div() diff --git a/crates/ui2/src/theme.rs b/crates/ui2/src/theme.rs index 00f20f5967..b585140cf7 100644 --- a/crates/ui2/src/theme.rs +++ b/crates/ui2/src/theme.rs @@ -132,10 +132,11 @@ where deserializer.deserialize_map(SyntaxVisitor) } -pub fn themed(theme: Theme, cx: &mut ViewContext, build_child: F) -> Themed +pub fn themed(theme: Theme, cx: &mut ViewContext, build_child: F) -> Themed where - E: Element, - F: FnOnce(&mut ViewContext) -> E, + V: 'static, + E: Element, + F: FnOnce(&mut ViewContext) -> E, { cx.default_global::().0.push(theme.clone()); let child = build_child(cx); @@ -148,12 +149,13 @@ pub struct Themed { pub(crate) child: E, } -impl IntoAnyElement for Themed +impl IntoAnyElement for Themed where - E: 'static + Element + Send + Sync, + V: 'static, + E: 'static + Element + Send + Sync, E::ElementState: Send + Sync, { - fn into_any(self) -> AnyElement { + fn into_any(self) -> AnyElement { AnyElement::new(self) } } @@ -161,11 +163,11 @@ where #[derive(Default)] struct ThemeStack(Vec); -impl Element for Themed +impl + Send + Sync> Element for Themed where + V: 'static, E::ElementState: Send + Sync, { - type ViewState = E::ViewState; type ElementState = E::ElementState; fn id(&self) -> Option { @@ -174,9 +176,9 @@ where fn initialize( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: Option, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::ElementState { cx.default_global::().0.push(self.theme.clone()); let element_state = self.child.initialize(view_state, element_state, cx); @@ -186,9 +188,9 @@ where fn layout( &mut self, - view_state: &mut E::ViewState, + view_state: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> LayoutId where Self: Sized, @@ -202,9 +204,9 @@ where fn paint( &mut self, bounds: Bounds, - view_state: &mut Self::ViewState, + view_state: &mut V, frame_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) where Self: Sized, { From 4266ead9589b644133560b2003cc6a2ebdbb304a Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 26 Oct 2023 10:46:02 +0200 Subject: [PATCH 05/24] WIP: Trait bounds --- crates/gpui2/src/element.rs | 4 +- crates/ui2/src/components/panes.rs | 77 ++++++++++++++---------------- 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index c6707049a6..3b53884e35 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -8,6 +8,8 @@ pub trait Element: IntoAnyElement { fn id(&self) -> Option; + /// Called to initialize this element for the current frame. If this + /// element had state in a previous frame, it will be passed in for the 3rd argument. fn initialize( &mut self, view_state: &mut V, @@ -41,7 +43,7 @@ pub trait Element: IntoAnyElement { #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)] pub struct GlobalElementId(SmallVec<[ElementId; 32]>); -pub trait ParentElement: Element { +pub trait ParentElement { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; fn child(mut self, child: impl IntoAnyElement) -> Self diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index 0c2714916b..789898cb9d 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -23,56 +23,54 @@ pub struct Pane { impl IntoAnyElement for Pane { fn into_any(self) -> AnyElement { - ElementRenderer { - id: Some(self.id), - render: Some(move |view_state, cx| self.render(view_state, cx)), + let render = move |view_state, cx| self.render(view_state, cx); + + AnyElement::new(ElementRenderer { + render: Some(render), view_type: PhantomData, element_type: PhantomData, - } + }) } } struct ElementRenderer where - E: IntoAnyElement, - F: FnOnce(&mut V, &mut ViewContext) -> E, + V: 'static + Send + Sync, + E: 'static + IntoAnyElement + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext) -> E + 'static + Send + Sync, { - id: Option, render: Option, view_type: PhantomData, element_type: PhantomData, } -impl Element for ElementRenderer +impl Element for ElementRenderer where - V: 'static, - E: IntoAnyElement, - F: FnOnce(&mut V, &mut ViewContext) -> E, + V: 'static + Send + Sync, + E: 'static + IntoAnyElement + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext) -> E + 'static + Send + Sync, { - type ViewState = V; type ElementState = AnyElement; fn id(&self) -> Option { - self.id + None } fn initialize( &mut self, - view_state: &mut Self::ViewState, - rendered_element: Option, - cx: &mut ViewContext, + view_state: &mut V, + _element_state: Option, + cx: &mut ViewContext, ) -> Self::ElementState { - rendered_element.unwrap_or_else(|| { - let render = self.render.take().unwrap(); - (render)(view_state, cx) - }) + let render = self.render.take().unwrap(); + (render)(view_state, cx).into_any() } fn layout( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, rendered_element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> gpui2::LayoutId { rendered_element.layout(view_state, cx) } @@ -80,9 +78,9 @@ where fn paint( &mut self, bounds: gpui2::Bounds, - view_state: &mut Self::ViewState, + view_state: &mut V, rendered_element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { rendered_element.paint(view_state, cx) } @@ -90,16 +88,16 @@ where impl IntoAnyElement for ElementRenderer where - V: 'static, - E: IntoAnyElement, - F: FnOnce(&mut V, &mut ViewContext) -> E, + V: 'static + Send + Sync, + E: 'static + IntoAnyElement + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext) -> E + 'static + Send + Sync, { fn into_any(self) -> AnyElement { - self + AnyElement::new(self) } } -impl Pane { +impl Pane { pub fn new(id: impl Into, size: Size) -> Self { // Fill is only here for debugging purposes, remove before release @@ -118,7 +116,7 @@ impl Pane { self } - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(self, view: &mut V, cx: &mut ViewContext) -> Div> IntoAnyElement { div() .id(self.id.clone()) .flex() @@ -127,12 +125,7 @@ impl Pane { .w(self.size.width) .h(self.size.height) .relative() - .child( - div() - .z_index(0) - .size_full() - .children(self.children.drain(..)), - ) + .child(div().z_index(0).size_full().children(self.children)) .child( // TODO kb! Figure out why we can't we see the red background when we drag a file over this div. div() @@ -162,8 +155,8 @@ pub struct PaneGroup { split_direction: SplitDirection, } -impl PaneGroup { - pub fn new_groups(groups: Vec>, split_direction: SplitDirection) -> Self { +impl PaneGroup { + pub fn new_groups(groups: Vec>, split_direction: SplitDirection) -> Self { Self { state_type: PhantomData, groups, @@ -172,7 +165,7 @@ impl PaneGroup { } } - pub fn new_panes(panes: Vec>, split_direction: SplitDirection) -> Self { + pub fn new_panes(panes: Vec>, split_direction: SplitDirection) -> Self { Self { state_type: PhantomData, groups: Vec::new(), @@ -181,7 +174,7 @@ impl PaneGroup { } } - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, view: &mut V, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); if !self.panes.is_empty() { @@ -191,7 +184,7 @@ impl PaneGroup { .gap_px() .w_full() .h_full() - .children(self.panes.iter_mut().map(|pane| pane.render(view, cx))); + .children(self.panes.drain(..).map(|pane| pane.render(view, cx))); if self.split_direction == SplitDirection::Horizontal { return el; @@ -208,7 +201,7 @@ impl PaneGroup { .w_full() .h_full() .bg(theme.editor) - .children(self.groups.iter_mut().map(|group| group.render(view, cx))); + .children(self.groups.iter_mut().map(| group| group.render(view, cx))); if self.split_direction == SplitDirection::Horizontal { return el; From db7d12f6282bce538aa33a5b7d00bc24fe52f041 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Oct 2023 10:59:27 +0200 Subject: [PATCH 06/24] WIP --- crates/ui2/src/components/panes.rs | 53 ++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index 789898cb9d..8ad1d4091d 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -13,17 +13,18 @@ pub enum SplitDirection { } // #[derive(Element)] -pub struct Pane { +pub struct Pane { id: ElementId, - state_type: PhantomData, + state_type: PhantomData, size: Size, fill: Hsla, - children: SmallVec<[AnyElement; 2]>, + children: SmallVec<[AnyElement; 2]>, } impl IntoAnyElement for Pane { fn into_any(self) -> AnyElement { - let render = move |view_state, cx| self.render(view_state, cx); + let render = + move |view_state: &mut V, cx: &mut ViewContext<'_, '_, V>| self.render(view_state, cx); AnyElement::new(ElementRenderer { render: Some(render), @@ -35,20 +36,36 @@ impl IntoAnyElement for Pane { struct ElementRenderer where - V: 'static + Send + Sync, + V: 'static, E: 'static + IntoAnyElement + Send + Sync, - F: FnOnce(&mut V, &mut ViewContext) -> E + 'static + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static + Send + Sync, { render: Option, view_type: PhantomData, element_type: PhantomData, } +unsafe impl Send for ElementRenderer +where + V: 'static, + E: 'static + IntoAnyElement + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static + Send + Sync, +{ +} + +unsafe impl Sync for ElementRenderer +where + V: 'static, + E: 'static + IntoAnyElement + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static + Send + Sync, +{ +} + impl Element for ElementRenderer where - V: 'static + Send + Sync, + V: 'static, E: 'static + IntoAnyElement + Send + Sync, - F: FnOnce(&mut V, &mut ViewContext) -> E + 'static + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static + Send + Sync, { type ElementState = AnyElement; @@ -88,7 +105,7 @@ where impl IntoAnyElement for ElementRenderer where - V: 'static + Send + Sync, + V: 'static, E: 'static + IntoAnyElement + Send + Sync, F: FnOnce(&mut V, &mut ViewContext) -> E + 'static + Send + Sync, { @@ -97,7 +114,7 @@ where } } -impl Pane { +impl Pane { pub fn new(id: impl Into, size: Size) -> Self { // Fill is only here for debugging purposes, remove before release @@ -116,7 +133,7 @@ impl Pane { self } - fn render(self, view: &mut V, cx: &mut ViewContext) -> Div> IntoAnyElement { + fn render(self, view: &mut V, cx: &mut ViewContext) -> impl IntoAnyElement { div() .id(self.id.clone()) .flex() @@ -141,17 +158,17 @@ impl Pane { } } -impl ParentElement for Pane { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { +impl ParentElement for Pane { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } #[derive(Element)] -pub struct PaneGroup { - state_type: PhantomData, - groups: Vec>, - panes: Vec>, +pub struct PaneGroup { + state_type: PhantomData, + groups: Vec>, + panes: Vec>, split_direction: SplitDirection, } @@ -201,7 +218,7 @@ impl PaneGroup { .w_full() .h_full() .bg(theme.editor) - .children(self.groups.iter_mut().map(| group| group.render(view, cx))); + .children(self.groups.iter_mut().map(|group| group.render(view, cx))); if self.split_direction == SplitDirection::Horizontal { return el; From 45a8aea0f0a62b0cfd8c1f0e9787202222d4a499 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Oct 2023 11:21:42 +0200 Subject: [PATCH 07/24] Make FnOnces that render elements IntoAnyElement --- crates/gpui2/src/element.rs | 67 +++++++++++++++++++++ crates/ui2/src/components/panes.rs | 96 +----------------------------- 2 files changed, 70 insertions(+), 93 deletions(-) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index 3b53884e35..4b5e61be4a 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -180,6 +180,9 @@ where pub struct AnyElement(Box + Send + Sync>); +unsafe impl Send for AnyElement {} +unsafe impl Sync for AnyElement {} + impl AnyElement { pub fn new(element: E) -> Self where @@ -213,3 +216,67 @@ impl IntoAnyElement for AnyElement { self } } + +impl Element for Option +where + V: 'static, + E: 'static + IntoAnyElement + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + Sync + 'static, +{ + type ElementState = AnyElement; + + fn id(&self) -> Option { + None + } + + fn initialize( + &mut self, + view_state: &mut V, + _rendered_element: Option, + cx: &mut ViewContext, + ) -> Self::ElementState { + let render = self.take().unwrap(); + (render)(view_state, cx).into_any() + } + + fn layout( + &mut self, + view_state: &mut V, + rendered_element: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> LayoutId { + rendered_element.layout(view_state, cx) + } + + fn paint( + &mut self, + _bounds: Bounds, + view_state: &mut V, + rendered_element: &mut Self::ElementState, + cx: &mut ViewContext, + ) { + rendered_element.paint(view_state, cx) + } +} + +impl IntoAnyElement for Option +where + V: 'static, + E: 'static + IntoAnyElement + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + Sync + 'static, +{ + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + +impl IntoAnyElement for F +where + V: 'static, + E: 'static + IntoAnyElement + Send + Sync, + F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + Sync + 'static, +{ + fn into_any(self) -> AnyElement { + AnyElement::new(Some(self)) + } +} diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index 8ad1d4091d..229de3caa4 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -12,105 +12,17 @@ pub enum SplitDirection { Vertical, } -// #[derive(Element)] pub struct Pane { id: ElementId, - state_type: PhantomData, size: Size, fill: Hsla, children: SmallVec<[AnyElement; 2]>, } -impl IntoAnyElement for Pane { +impl IntoAnyElement for Pane { fn into_any(self) -> AnyElement { - let render = - move |view_state: &mut V, cx: &mut ViewContext<'_, '_, V>| self.render(view_state, cx); - - AnyElement::new(ElementRenderer { - render: Some(render), - view_type: PhantomData, - element_type: PhantomData, - }) - } -} - -struct ElementRenderer -where - V: 'static, - E: 'static + IntoAnyElement + Send + Sync, - F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static + Send + Sync, -{ - render: Option, - view_type: PhantomData, - element_type: PhantomData, -} - -unsafe impl Send for ElementRenderer -where - V: 'static, - E: 'static + IntoAnyElement + Send + Sync, - F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static + Send + Sync, -{ -} - -unsafe impl Sync for ElementRenderer -where - V: 'static, - E: 'static + IntoAnyElement + Send + Sync, - F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static + Send + Sync, -{ -} - -impl Element for ElementRenderer -where - V: 'static, - E: 'static + IntoAnyElement + Send + Sync, - F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static + Send + Sync, -{ - type ElementState = AnyElement; - - fn id(&self) -> Option { - None - } - - fn initialize( - &mut self, - view_state: &mut V, - _element_state: Option, - cx: &mut ViewContext, - ) -> Self::ElementState { - let render = self.render.take().unwrap(); - (render)(view_state, cx).into_any() - } - - fn layout( - &mut self, - view_state: &mut V, - rendered_element: &mut Self::ElementState, - cx: &mut ViewContext, - ) -> gpui2::LayoutId { - rendered_element.layout(view_state, cx) - } - - fn paint( - &mut self, - bounds: gpui2::Bounds, - view_state: &mut V, - rendered_element: &mut Self::ElementState, - cx: &mut ViewContext, - ) { - rendered_element.paint(view_state, cx) - } -} - -impl IntoAnyElement for ElementRenderer -where - V: 'static, - E: 'static + IntoAnyElement + Send + Sync, - F: FnOnce(&mut V, &mut ViewContext) -> E + 'static + Send + Sync, -{ - fn into_any(self) -> AnyElement { - AnyElement::new(self) + (move |view_state: &mut V, cx: &mut ViewContext<'_, '_, V>| self.render(view_state, cx)) + .into_any() } } @@ -120,10 +32,8 @@ impl Pane { Self { id: id.into(), - state_type: PhantomData, size, fill: hsla(0.3, 0.3, 0.3, 1.), - // fill: system_color.transparent, children: SmallVec::new(), } } From db15db45ce5114571112f617d13ca11b754c6adf Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Oct 2023 11:31:47 +0200 Subject: [PATCH 08/24] WIP --- crates/gpui2/src/element.rs | 2 +- crates/gpui2/src/interactive.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index 4b5e61be4a..87e1e5c836 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -3,7 +3,7 @@ use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; use std::{any::Any, mem}; -pub trait Element: IntoAnyElement { +pub trait Element { type ElementState: 'static; fn id(&self) -> Option; diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index f00e24b472..f51516dbe5 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -1,7 +1,7 @@ use crate::{ point, px, view, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, DispatchContext, - DispatchPhase, Element, ElementId, FocusHandle, KeyMatch, Keystroke, Modifiers, Overflow, - Pixels, Point, SharedString, Size, Style, StyleRefinement, ViewContext, + DispatchPhase, Element, ElementId, FocusHandle, IntoAnyElement, KeyMatch, Keystroke, Modifiers, + Overflow, Pixels, Point, SharedString, Size, Style, StyleRefinement, ViewContext, }; use collections::HashMap; use derive_more::{Deref, DerefMut}; @@ -327,7 +327,7 @@ pub trait StatefulInteractive: StatelessInteractive { S: Any + Send + Sync, R: Fn(&mut V, &mut ViewContext) -> E, R: 'static + Send + Sync, - E: Element, + E: IntoAnyElement, { debug_assert!( self.stateful_interaction().drag_listener.is_none(), @@ -871,7 +871,7 @@ pub struct Drag where R: Fn(&mut V, &mut ViewContext) -> E, V: 'static, - E: Element, + E: IntoAnyElement, { pub state: S, pub render_drag_handle: R, @@ -882,7 +882,7 @@ impl Drag where R: Fn(&mut V, &mut ViewContext) -> E, V: 'static, - E: Element, + E: IntoAnyElement, { pub fn new(state: S, render_drag_handle: R) -> Self { Drag { From 71ad3e1b204135b724979c2c3b22747c5b083aa8 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 26 Oct 2023 11:48:25 +0200 Subject: [PATCH 09/24] Add rpc2 --- crates/rpc2/Cargo.toml | 44 + crates/rpc2/build.rs | 8 + crates/rpc2/proto/zed.proto | 1559 +++++++++++++++++++++++++++++++++++ crates/rpc2/src/auth.rs | 136 +++ crates/rpc2/src/conn.rs | 112 +++ crates/rpc2/src/macros.rs | 70 ++ crates/rpc2/src/peer.rs | 933 +++++++++++++++++++++ crates/rpc2/src/proto.rs | 674 +++++++++++++++ crates/rpc2/src/rpc.rs | 9 + 9 files changed, 3545 insertions(+) create mode 100644 crates/rpc2/Cargo.toml create mode 100644 crates/rpc2/build.rs create mode 100644 crates/rpc2/proto/zed.proto create mode 100644 crates/rpc2/src/auth.rs create mode 100644 crates/rpc2/src/conn.rs create mode 100644 crates/rpc2/src/macros.rs create mode 100644 crates/rpc2/src/peer.rs create mode 100644 crates/rpc2/src/proto.rs create mode 100644 crates/rpc2/src/rpc.rs diff --git a/crates/rpc2/Cargo.toml b/crates/rpc2/Cargo.toml new file mode 100644 index 0000000000..3c307be4fb --- /dev/null +++ b/crates/rpc2/Cargo.toml @@ -0,0 +1,44 @@ +[package] +description = "Shared logic for communication between the Zed app and the zed.dev server" +edition = "2021" +name = "rpc" +version = "0.1.0" +publish = false + +[lib] +path = "src/rpc.rs" +doctest = false + +[features] +test-support = ["collections/test-support", "gpui/test-support"] + +[dependencies] +clock = { path = "../clock" } +collections = { path = "../collections" } +gpui = { path = "../gpui", optional = true } +util = { path = "../util" } +anyhow.workspace = true +async-lock = "2.4" +async-tungstenite = "0.16" +base64 = "0.13" +futures.workspace = true +parking_lot.workspace = true +prost.workspace = true +rand.workspace = true +rsa = "0.4" +serde.workspace = true +serde_derive.workspace = true +smol-timeout = "0.6" +tracing = { version = "0.1.34", features = ["log"] } +zstd = "0.11" + +[build-dependencies] +prost-build = "0.9" + +[dev-dependencies] +collections = { path = "../collections", features = ["test-support"] } +gpui = { path = "../gpui", features = ["test-support"] } +smol.workspace = true +tempdir.workspace = true +ctor.workspace = true +env_logger.workspace = true diff --git a/crates/rpc2/build.rs b/crates/rpc2/build.rs new file mode 100644 index 0000000000..66b289f1db --- /dev/null +++ b/crates/rpc2/build.rs @@ -0,0 +1,8 @@ +fn main() { + let mut build = prost_build::Config::new(); + // build.protoc_arg("--experimental_allow_proto3_optional"); + build + .type_attribute(".", "#[derive(serde::Serialize)]") + .compile_protos(&["proto/zed.proto"], &["proto"]) + .unwrap(); +} diff --git a/crates/rpc2/proto/zed.proto b/crates/rpc2/proto/zed.proto new file mode 100644 index 0000000000..3501e70e6a --- /dev/null +++ b/crates/rpc2/proto/zed.proto @@ -0,0 +1,1559 @@ +syntax = "proto3"; +package zed.messages; + +// Looking for a number? Search "// Current max" + +message PeerId { + uint32 owner_id = 1; + uint32 id = 2; +} + +message Envelope { + uint32 id = 1; + optional uint32 responding_to = 2; + optional PeerId original_sender_id = 3; + oneof payload { + Hello hello = 4; + Ack ack = 5; + Error error = 6; + Ping ping = 7; + Test test = 8; + + CreateRoom create_room = 9; + CreateRoomResponse create_room_response = 10; + JoinRoom join_room = 11; + JoinRoomResponse join_room_response = 12; + RejoinRoom rejoin_room = 13; + RejoinRoomResponse rejoin_room_response = 14; + LeaveRoom leave_room = 15; + Call call = 16; + IncomingCall incoming_call = 17; + CallCanceled call_canceled = 18; + CancelCall cancel_call = 19; + DeclineCall decline_call = 20; + UpdateParticipantLocation update_participant_location = 21; + RoomUpdated room_updated = 22; + + ShareProject share_project = 23; + ShareProjectResponse share_project_response = 24; + UnshareProject unshare_project = 25; + JoinProject join_project = 26; + JoinProjectResponse join_project_response = 27; + LeaveProject leave_project = 28; + AddProjectCollaborator add_project_collaborator = 29; + UpdateProjectCollaborator update_project_collaborator = 30; + RemoveProjectCollaborator remove_project_collaborator = 31; + + GetDefinition get_definition = 32; + GetDefinitionResponse get_definition_response = 33; + GetTypeDefinition get_type_definition = 34; + GetTypeDefinitionResponse get_type_definition_response = 35; + GetReferences get_references = 36; + GetReferencesResponse get_references_response = 37; + GetDocumentHighlights get_document_highlights = 38; + GetDocumentHighlightsResponse get_document_highlights_response = 39; + GetProjectSymbols get_project_symbols = 40; + GetProjectSymbolsResponse get_project_symbols_response = 41; + OpenBufferForSymbol open_buffer_for_symbol = 42; + OpenBufferForSymbolResponse open_buffer_for_symbol_response = 43; + + UpdateProject update_project = 44; + UpdateWorktree update_worktree = 45; + + CreateProjectEntry create_project_entry = 46; + RenameProjectEntry rename_project_entry = 47; + CopyProjectEntry copy_project_entry = 48; + DeleteProjectEntry delete_project_entry = 49; + ProjectEntryResponse project_entry_response = 50; + ExpandProjectEntry expand_project_entry = 51; + ExpandProjectEntryResponse expand_project_entry_response = 52; + + UpdateDiagnosticSummary update_diagnostic_summary = 53; + StartLanguageServer start_language_server = 54; + UpdateLanguageServer update_language_server = 55; + + OpenBufferById open_buffer_by_id = 56; + OpenBufferByPath open_buffer_by_path = 57; + OpenBufferResponse open_buffer_response = 58; + CreateBufferForPeer create_buffer_for_peer = 59; + UpdateBuffer update_buffer = 60; + UpdateBufferFile update_buffer_file = 61; + SaveBuffer save_buffer = 62; + BufferSaved buffer_saved = 63; + BufferReloaded buffer_reloaded = 64; + ReloadBuffers reload_buffers = 65; + ReloadBuffersResponse reload_buffers_response = 66; + SynchronizeBuffers synchronize_buffers = 67; + SynchronizeBuffersResponse synchronize_buffers_response = 68; + FormatBuffers format_buffers = 69; + FormatBuffersResponse format_buffers_response = 70; + GetCompletions get_completions = 71; + GetCompletionsResponse get_completions_response = 72; + ApplyCompletionAdditionalEdits apply_completion_additional_edits = 73; + ApplyCompletionAdditionalEditsResponse apply_completion_additional_edits_response = 74; + GetCodeActions get_code_actions = 75; + GetCodeActionsResponse get_code_actions_response = 76; + GetHover get_hover = 77; + GetHoverResponse get_hover_response = 78; + ApplyCodeAction apply_code_action = 79; + ApplyCodeActionResponse apply_code_action_response = 80; + PrepareRename prepare_rename = 81; + PrepareRenameResponse prepare_rename_response = 82; + PerformRename perform_rename = 83; + PerformRenameResponse perform_rename_response = 84; + SearchProject search_project = 85; + SearchProjectResponse search_project_response = 86; + + UpdateContacts update_contacts = 87; + UpdateInviteInfo update_invite_info = 88; + ShowContacts show_contacts = 89; + + GetUsers get_users = 90; + FuzzySearchUsers fuzzy_search_users = 91; + UsersResponse users_response = 92; + RequestContact request_contact = 93; + RespondToContactRequest respond_to_contact_request = 94; + RemoveContact remove_contact = 95; + + Follow follow = 96; + FollowResponse follow_response = 97; + UpdateFollowers update_followers = 98; + Unfollow unfollow = 99; + GetPrivateUserInfo get_private_user_info = 100; + GetPrivateUserInfoResponse get_private_user_info_response = 101; + UpdateDiffBase update_diff_base = 102; + + OnTypeFormatting on_type_formatting = 103; + OnTypeFormattingResponse on_type_formatting_response = 104; + + UpdateWorktreeSettings update_worktree_settings = 105; + + InlayHints inlay_hints = 106; + InlayHintsResponse inlay_hints_response = 107; + ResolveInlayHint resolve_inlay_hint = 108; + ResolveInlayHintResponse resolve_inlay_hint_response = 109; + RefreshInlayHints refresh_inlay_hints = 110; + + CreateChannel create_channel = 111; + CreateChannelResponse create_channel_response = 112; + InviteChannelMember invite_channel_member = 113; + RemoveChannelMember remove_channel_member = 114; + RespondToChannelInvite respond_to_channel_invite = 115; + UpdateChannels update_channels = 116; + JoinChannel join_channel = 117; + DeleteChannel delete_channel = 118; + GetChannelMembers get_channel_members = 119; + GetChannelMembersResponse get_channel_members_response = 120; + SetChannelMemberAdmin set_channel_member_admin = 121; + RenameChannel rename_channel = 122; + RenameChannelResponse rename_channel_response = 123; + + JoinChannelBuffer join_channel_buffer = 124; + JoinChannelBufferResponse join_channel_buffer_response = 125; + UpdateChannelBuffer update_channel_buffer = 126; + LeaveChannelBuffer leave_channel_buffer = 127; + UpdateChannelBufferCollaborators update_channel_buffer_collaborators = 128; + RejoinChannelBuffers rejoin_channel_buffers = 129; + RejoinChannelBuffersResponse rejoin_channel_buffers_response = 130; + AckBufferOperation ack_buffer_operation = 143; + + JoinChannelChat join_channel_chat = 131; + JoinChannelChatResponse join_channel_chat_response = 132; + LeaveChannelChat leave_channel_chat = 133; + SendChannelMessage send_channel_message = 134; + SendChannelMessageResponse send_channel_message_response = 135; + ChannelMessageSent channel_message_sent = 136; + GetChannelMessages get_channel_messages = 137; + GetChannelMessagesResponse get_channel_messages_response = 138; + RemoveChannelMessage remove_channel_message = 139; + AckChannelMessage ack_channel_message = 144; + + LinkChannel link_channel = 140; + UnlinkChannel unlink_channel = 141; + MoveChannel move_channel = 142; // current max: 144 + } +} + +// Messages + +message Hello { + PeerId peer_id = 1; +} + +message Ping {} + +message Ack {} + +message Error { + string message = 1; +} + +message Test { + uint64 id = 1; +} + +message CreateRoom {} + +message CreateRoomResponse { + Room room = 1; + optional LiveKitConnectionInfo live_kit_connection_info = 2; +} + +message JoinRoom { + uint64 id = 1; +} + +message JoinRoomResponse { + Room room = 1; + optional uint64 channel_id = 2; + optional LiveKitConnectionInfo live_kit_connection_info = 3; +} + +message RejoinRoom { + uint64 id = 1; + repeated UpdateProject reshared_projects = 2; + repeated RejoinProject rejoined_projects = 3; +} + +message RejoinProject { + uint64 id = 1; + repeated RejoinWorktree worktrees = 2; +} + +message RejoinWorktree { + uint64 id = 1; + uint64 scan_id = 2; +} + +message RejoinRoomResponse { + Room room = 1; + repeated ResharedProject reshared_projects = 2; + repeated RejoinedProject rejoined_projects = 3; +} + +message ResharedProject { + uint64 id = 1; + repeated Collaborator collaborators = 2; +} + +message RejoinedProject { + uint64 id = 1; + repeated WorktreeMetadata worktrees = 2; + repeated Collaborator collaborators = 3; + repeated LanguageServer language_servers = 4; +} + +message LeaveRoom {} + +message Room { + uint64 id = 1; + repeated Participant participants = 2; + repeated PendingParticipant pending_participants = 3; + repeated Follower followers = 4; + string live_kit_room = 5; +} + +message Participant { + uint64 user_id = 1; + PeerId peer_id = 2; + repeated ParticipantProject projects = 3; + ParticipantLocation location = 4; + uint32 participant_index = 5; +} + +message PendingParticipant { + uint64 user_id = 1; + uint64 calling_user_id = 2; + optional uint64 initial_project_id = 3; +} + +message ParticipantProject { + uint64 id = 1; + repeated string worktree_root_names = 2; +} + +message Follower { + PeerId leader_id = 1; + PeerId follower_id = 2; + uint64 project_id = 3; +} + +message ParticipantLocation { + oneof variant { + SharedProject shared_project = 1; + UnsharedProject unshared_project = 2; + External external = 3; + } + + message SharedProject { + uint64 id = 1; + } + + message UnsharedProject {} + + message External {} +} + +message Call { + uint64 room_id = 1; + uint64 called_user_id = 2; + optional uint64 initial_project_id = 3; +} + +message IncomingCall { + uint64 room_id = 1; + uint64 calling_user_id = 2; + repeated uint64 participant_user_ids = 3; + optional ParticipantProject initial_project = 4; +} + +message CallCanceled { + uint64 room_id = 1; +} + +message CancelCall { + uint64 room_id = 1; + uint64 called_user_id = 2; +} + +message DeclineCall { + uint64 room_id = 1; +} + +message UpdateParticipantLocation { + uint64 room_id = 1; + ParticipantLocation location = 2; +} + +message RoomUpdated { + Room room = 1; +} + +message LiveKitConnectionInfo { + string server_url = 1; + string token = 2; +} + +message ShareProject { + uint64 room_id = 1; + repeated WorktreeMetadata worktrees = 2; +} + +message ShareProjectResponse { + uint64 project_id = 1; +} + +message UnshareProject { + uint64 project_id = 1; +} + +message UpdateProject { + uint64 project_id = 1; + repeated WorktreeMetadata worktrees = 2; +} + +message JoinProject { + uint64 project_id = 1; +} + +message JoinProjectResponse { + uint32 replica_id = 1; + repeated WorktreeMetadata worktrees = 2; + repeated Collaborator collaborators = 3; + repeated LanguageServer language_servers = 4; +} + +message LeaveProject { + uint64 project_id = 1; +} + +message UpdateWorktree { + uint64 project_id = 1; + uint64 worktree_id = 2; + string root_name = 3; + repeated Entry updated_entries = 4; + repeated uint64 removed_entries = 5; + repeated RepositoryEntry updated_repositories = 6; + repeated uint64 removed_repositories = 7; + uint64 scan_id = 8; + bool is_last_update = 9; + string abs_path = 10; +} + +message UpdateWorktreeSettings { + uint64 project_id = 1; + uint64 worktree_id = 2; + string path = 3; + optional string content = 4; +} + +message CreateProjectEntry { + uint64 project_id = 1; + uint64 worktree_id = 2; + string path = 3; + bool is_directory = 4; +} + +message RenameProjectEntry { + uint64 project_id = 1; + uint64 entry_id = 2; + string new_path = 3; +} + +message CopyProjectEntry { + uint64 project_id = 1; + uint64 entry_id = 2; + string new_path = 3; +} + +message DeleteProjectEntry { + uint64 project_id = 1; + uint64 entry_id = 2; +} + +message ExpandProjectEntry { + uint64 project_id = 1; + uint64 entry_id = 2; +} + +message ExpandProjectEntryResponse { + uint64 worktree_scan_id = 1; +} + +message ProjectEntryResponse { + Entry entry = 1; + uint64 worktree_scan_id = 2; +} + +message AddProjectCollaborator { + uint64 project_id = 1; + Collaborator collaborator = 2; +} + +message UpdateProjectCollaborator { + uint64 project_id = 1; + PeerId old_peer_id = 2; + PeerId new_peer_id = 3; +} + +message RemoveProjectCollaborator { + uint64 project_id = 1; + PeerId peer_id = 2; +} + +message UpdateChannelBufferCollaborators { + uint64 channel_id = 1; + repeated Collaborator collaborators = 2; +} + +message GetDefinition { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + repeated VectorClockEntry version = 4; + } + +message GetDefinitionResponse { + repeated LocationLink links = 1; +} + +message GetTypeDefinition { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + repeated VectorClockEntry version = 4; + } + +message GetTypeDefinitionResponse { + repeated LocationLink links = 1; +} + +message GetReferences { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + repeated VectorClockEntry version = 4; + } + +message GetReferencesResponse { + repeated Location locations = 1; +} + +message GetDocumentHighlights { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + repeated VectorClockEntry version = 4; + } + +message GetDocumentHighlightsResponse { + repeated DocumentHighlight highlights = 1; +} + +message Location { + uint64 buffer_id = 1; + Anchor start = 2; + Anchor end = 3; +} + +message LocationLink { + optional Location origin = 1; + Location target = 2; +} + +message DocumentHighlight { + Kind kind = 1; + Anchor start = 2; + Anchor end = 3; + + enum Kind { + Text = 0; + Read = 1; + Write = 2; + } +} + +message GetProjectSymbols { + uint64 project_id = 1; + string query = 2; +} + +message GetProjectSymbolsResponse { + repeated Symbol symbols = 4; +} + +message Symbol { + uint64 source_worktree_id = 1; + uint64 worktree_id = 2; + string language_server_name = 3; + string name = 4; + int32 kind = 5; + string path = 6; + // Cannot use generate anchors for unopened files, + // so we are forced to use point coords instead + PointUtf16 start = 7; + PointUtf16 end = 8; + bytes signature = 9; +} + +message OpenBufferForSymbol { + uint64 project_id = 1; + Symbol symbol = 2; +} + +message OpenBufferForSymbolResponse { + uint64 buffer_id = 1; +} + +message OpenBufferByPath { + uint64 project_id = 1; + uint64 worktree_id = 2; + string path = 3; +} + +message OpenBufferById { + uint64 project_id = 1; + uint64 id = 2; +} + +message OpenBufferResponse { + uint64 buffer_id = 1; +} + +message CreateBufferForPeer { + uint64 project_id = 1; + PeerId peer_id = 2; + oneof variant { + BufferState state = 3; + BufferChunk chunk = 4; + } +} + +message UpdateBuffer { + uint64 project_id = 1; + uint64 buffer_id = 2; + repeated Operation operations = 3; +} + +message UpdateChannelBuffer { + uint64 channel_id = 1; + repeated Operation operations = 2; +} + +message UpdateBufferFile { + uint64 project_id = 1; + uint64 buffer_id = 2; + File file = 3; +} + +message SaveBuffer { + uint64 project_id = 1; + uint64 buffer_id = 2; + repeated VectorClockEntry version = 3; +} + +message BufferSaved { + uint64 project_id = 1; + uint64 buffer_id = 2; + repeated VectorClockEntry version = 3; + Timestamp mtime = 4; + string fingerprint = 5; +} + +message BufferReloaded { + uint64 project_id = 1; + uint64 buffer_id = 2; + repeated VectorClockEntry version = 3; + Timestamp mtime = 4; + string fingerprint = 5; + LineEnding line_ending = 6; +} + +message ReloadBuffers { + uint64 project_id = 1; + repeated uint64 buffer_ids = 2; +} + +message ReloadBuffersResponse { + ProjectTransaction transaction = 1; +} + +message SynchronizeBuffers { + uint64 project_id = 1; + repeated BufferVersion buffers = 2; +} + +message SynchronizeBuffersResponse { + repeated BufferVersion buffers = 1; +} + +message BufferVersion { + uint64 id = 1; + repeated VectorClockEntry version = 2; +} + +message ChannelBufferVersion { + uint64 channel_id = 1; + repeated VectorClockEntry version = 2; + uint64 epoch = 3; +} + +enum FormatTrigger { + Save = 0; + Manual = 1; +} + +message FormatBuffers { + uint64 project_id = 1; + FormatTrigger trigger = 2; + repeated uint64 buffer_ids = 3; +} + +message FormatBuffersResponse { + ProjectTransaction transaction = 1; +} + +message GetCompletions { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + repeated VectorClockEntry version = 4; +} + +message GetCompletionsResponse { + repeated Completion completions = 1; + repeated VectorClockEntry version = 2; +} + +message ApplyCompletionAdditionalEdits { + uint64 project_id = 1; + uint64 buffer_id = 2; + Completion completion = 3; +} + +message ApplyCompletionAdditionalEditsResponse { + Transaction transaction = 1; +} + +message Completion { + Anchor old_start = 1; + Anchor old_end = 2; + string new_text = 3; + uint64 server_id = 4; + bytes lsp_completion = 5; +} + +message GetCodeActions { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor start = 3; + Anchor end = 4; + repeated VectorClockEntry version = 5; +} + +message GetCodeActionsResponse { + repeated CodeAction actions = 1; + repeated VectorClockEntry version = 2; +} + +message GetHover { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + repeated VectorClockEntry version = 5; +} + +message GetHoverResponse { + optional Anchor start = 1; + optional Anchor end = 2; + repeated HoverBlock contents = 3; +} + +message HoverBlock { + string text = 1; + optional string language = 2; + bool is_markdown = 3; +} + +message ApplyCodeAction { + uint64 project_id = 1; + uint64 buffer_id = 2; + CodeAction action = 3; +} + +message ApplyCodeActionResponse { + ProjectTransaction transaction = 1; +} + +message PrepareRename { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + repeated VectorClockEntry version = 4; +} + +message PrepareRenameResponse { + bool can_rename = 1; + Anchor start = 2; + Anchor end = 3; + repeated VectorClockEntry version = 4; +} + +message PerformRename { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + string new_name = 4; + repeated VectorClockEntry version = 5; +} + +message OnTypeFormatting { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + string trigger = 4; + repeated VectorClockEntry version = 5; +} + +message OnTypeFormattingResponse { + Transaction transaction = 1; +} + +message InlayHints { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor start = 3; + Anchor end = 4; + repeated VectorClockEntry version = 5; +} + +message InlayHintsResponse { + repeated InlayHint hints = 1; + repeated VectorClockEntry version = 2; +} + +message InlayHint { + Anchor position = 1; + InlayHintLabel label = 2; + optional string kind = 3; + bool padding_left = 4; + bool padding_right = 5; + InlayHintTooltip tooltip = 6; + ResolveState resolve_state = 7; +} + +message InlayHintLabel { + oneof label { + string value = 1; + InlayHintLabelParts label_parts = 2; + } +} + +message InlayHintLabelParts { + repeated InlayHintLabelPart parts = 1; +} + +message InlayHintLabelPart { + string value = 1; + InlayHintLabelPartTooltip tooltip = 2; + optional string location_url = 3; + PointUtf16 location_range_start = 4; + PointUtf16 location_range_end = 5; + optional uint64 language_server_id = 6; +} + +message InlayHintTooltip { + oneof content { + string value = 1; + MarkupContent markup_content = 2; + } +} + +message InlayHintLabelPartTooltip { + oneof content { + string value = 1; + MarkupContent markup_content = 2; + } +} + +message ResolveState { + State state = 1; + LspResolveState lsp_resolve_state = 2; + + enum State { + Resolved = 0; + CanResolve = 1; + Resolving = 2; + } + + message LspResolveState { + string value = 1; + uint64 server_id = 2; + } +} + +message ResolveInlayHint { + uint64 project_id = 1; + uint64 buffer_id = 2; + uint64 language_server_id = 3; + InlayHint hint = 4; +} + +message ResolveInlayHintResponse { + InlayHint hint = 1; +} + +message RefreshInlayHints { + uint64 project_id = 1; +} + +message MarkupContent { + bool is_markdown = 1; + string value = 2; +} + +message PerformRenameResponse { + ProjectTransaction transaction = 2; +} + +message SearchProject { + uint64 project_id = 1; + string query = 2; + bool regex = 3; + bool whole_word = 4; + bool case_sensitive = 5; + string files_to_include = 6; + string files_to_exclude = 7; +} + +message SearchProjectResponse { + repeated Location locations = 1; +} + +message CodeAction { + uint64 server_id = 1; + Anchor start = 2; + Anchor end = 3; + bytes lsp_action = 4; +} + +message ProjectTransaction { + repeated uint64 buffer_ids = 1; + repeated Transaction transactions = 2; +} + +message Transaction { + LamportTimestamp id = 1; + repeated LamportTimestamp edit_ids = 2; + repeated VectorClockEntry start = 3; +} + +message LamportTimestamp { + uint32 replica_id = 1; + uint32 value = 2; +} + +message LanguageServer { + uint64 id = 1; + string name = 2; +} + +message StartLanguageServer { + uint64 project_id = 1; + LanguageServer server = 2; +} + +message UpdateDiagnosticSummary { + uint64 project_id = 1; + uint64 worktree_id = 2; + DiagnosticSummary summary = 3; +} + +message DiagnosticSummary { + string path = 1; + uint64 language_server_id = 2; + uint32 error_count = 3; + uint32 warning_count = 4; +} + +message UpdateLanguageServer { + uint64 project_id = 1; + uint64 language_server_id = 2; + oneof variant { + LspWorkStart work_start = 3; + LspWorkProgress work_progress = 4; + LspWorkEnd work_end = 5; + LspDiskBasedDiagnosticsUpdating disk_based_diagnostics_updating = 6; + LspDiskBasedDiagnosticsUpdated disk_based_diagnostics_updated = 7; + } +} + +message LspWorkStart { + string token = 1; + optional string message = 2; + optional uint32 percentage = 3; +} + +message LspWorkProgress { + string token = 1; + optional string message = 2; + optional uint32 percentage = 3; +} + +message LspWorkEnd { + string token = 1; +} + +message LspDiskBasedDiagnosticsUpdating {} + +message LspDiskBasedDiagnosticsUpdated {} + +message UpdateChannels { + repeated Channel channels = 1; + repeated ChannelEdge insert_edge = 2; + repeated ChannelEdge delete_edge = 3; + repeated uint64 delete_channels = 4; + repeated Channel channel_invitations = 5; + repeated uint64 remove_channel_invitations = 6; + repeated ChannelParticipants channel_participants = 7; + repeated ChannelPermission channel_permissions = 8; + repeated UnseenChannelMessage unseen_channel_messages = 9; + repeated UnseenChannelBufferChange unseen_channel_buffer_changes = 10; +} + +message UnseenChannelMessage { + uint64 channel_id = 1; + uint64 message_id = 2; +} + +message UnseenChannelBufferChange { + uint64 channel_id = 1; + uint64 epoch = 2; + repeated VectorClockEntry version = 3; +} + +message ChannelEdge { + uint64 channel_id = 1; + uint64 parent_id = 2; +} + +message ChannelPermission { + uint64 channel_id = 1; + bool is_admin = 2; +} + +message ChannelParticipants { + uint64 channel_id = 1; + repeated uint64 participant_user_ids = 2; +} + +message JoinChannel { + uint64 channel_id = 1; +} + +message DeleteChannel { + uint64 channel_id = 1; +} + +message GetChannelMembers { + uint64 channel_id = 1; +} + +message GetChannelMembersResponse { + repeated ChannelMember members = 1; +} + +message ChannelMember { + uint64 user_id = 1; + bool admin = 2; + Kind kind = 3; + + enum Kind { + Member = 0; + Invitee = 1; + AncestorMember = 2; + } +} + +message CreateChannel { + string name = 1; + optional uint64 parent_id = 2; +} + +message CreateChannelResponse { + Channel channel = 1; + optional uint64 parent_id = 2; +} + +message InviteChannelMember { + uint64 channel_id = 1; + uint64 user_id = 2; + bool admin = 3; +} + +message RemoveChannelMember { + uint64 channel_id = 1; + uint64 user_id = 2; +} + +message SetChannelMemberAdmin { + uint64 channel_id = 1; + uint64 user_id = 2; + bool admin = 3; +} + +message RenameChannel { + uint64 channel_id = 1; + string name = 2; +} + +message RenameChannelResponse { + Channel channel = 1; +} + +message JoinChannelChat { + uint64 channel_id = 1; +} + +message JoinChannelChatResponse { + repeated ChannelMessage messages = 1; + bool done = 2; +} + +message LeaveChannelChat { + uint64 channel_id = 1; +} + +message SendChannelMessage { + uint64 channel_id = 1; + string body = 2; + Nonce nonce = 3; +} + +message RemoveChannelMessage { + uint64 channel_id = 1; + uint64 message_id = 2; +} + +message AckChannelMessage { + uint64 channel_id = 1; + uint64 message_id = 2; +} + +message SendChannelMessageResponse { + ChannelMessage message = 1; +} + +message ChannelMessageSent { + uint64 channel_id = 1; + ChannelMessage message = 2; +} + +message GetChannelMessages { + uint64 channel_id = 1; + uint64 before_message_id = 2; +} + +message GetChannelMessagesResponse { + repeated ChannelMessage messages = 1; + bool done = 2; +} + +message LinkChannel { + uint64 channel_id = 1; + uint64 to = 2; +} + +message UnlinkChannel { + uint64 channel_id = 1; + uint64 from = 2; +} + +message MoveChannel { + uint64 channel_id = 1; + uint64 from = 2; + uint64 to = 3; +} + +message JoinChannelBuffer { + uint64 channel_id = 1; +} + +message ChannelMessage { + uint64 id = 1; + string body = 2; + uint64 timestamp = 3; + uint64 sender_id = 4; + Nonce nonce = 5; +} + +message RejoinChannelBuffers { + repeated ChannelBufferVersion buffers = 1; +} + +message RejoinChannelBuffersResponse { + repeated RejoinedChannelBuffer buffers = 1; +} + +message AckBufferOperation { + uint64 buffer_id = 1; + uint64 epoch = 2; + repeated VectorClockEntry version = 3; +} + +message JoinChannelBufferResponse { + uint64 buffer_id = 1; + uint32 replica_id = 2; + string base_text = 3; + repeated Operation operations = 4; + repeated Collaborator collaborators = 5; + uint64 epoch = 6; +} + +message RejoinedChannelBuffer { + uint64 channel_id = 1; + repeated VectorClockEntry version = 2; + repeated Operation operations = 3; + repeated Collaborator collaborators = 4; +} + +message LeaveChannelBuffer { + uint64 channel_id = 1; +} + +message RespondToChannelInvite { + uint64 channel_id = 1; + bool accept = 2; +} + +message GetUsers { + repeated uint64 user_ids = 1; +} + +message FuzzySearchUsers { + string query = 1; +} + +message UsersResponse { + repeated User users = 1; +} + +message RequestContact { + uint64 responder_id = 1; +} + +message RemoveContact { + uint64 user_id = 1; +} + +message RespondToContactRequest { + uint64 requester_id = 1; + ContactRequestResponse response = 2; +} + +enum ContactRequestResponse { + Accept = 0; + Decline = 1; + Block = 2; + Dismiss = 3; +} + +message UpdateContacts { + repeated Contact contacts = 1; + repeated uint64 remove_contacts = 2; + repeated IncomingContactRequest incoming_requests = 3; + repeated uint64 remove_incoming_requests = 4; + repeated uint64 outgoing_requests = 5; + repeated uint64 remove_outgoing_requests = 6; +} + +message UpdateInviteInfo { + string url = 1; + uint32 count = 2; +} + +message ShowContacts {} + +message IncomingContactRequest { + uint64 requester_id = 1; + bool should_notify = 2; +} + +message UpdateDiagnostics { + uint32 replica_id = 1; + uint32 lamport_timestamp = 2; + uint64 server_id = 3; + repeated Diagnostic diagnostics = 4; +} + +message Follow { + uint64 room_id = 1; + optional uint64 project_id = 2; + PeerId leader_id = 3; +} + +message FollowResponse { + optional ViewId active_view_id = 1; + repeated View views = 2; +} + +message UpdateFollowers { + uint64 room_id = 1; + optional uint64 project_id = 2; + repeated PeerId follower_ids = 3; + oneof variant { + UpdateActiveView update_active_view = 4; + View create_view = 5; + UpdateView update_view = 6; + } +} + +message Unfollow { + uint64 room_id = 1; + optional uint64 project_id = 2; + PeerId leader_id = 3; +} + +message GetPrivateUserInfo {} + +message GetPrivateUserInfoResponse { + string metrics_id = 1; + bool staff = 2; + repeated string flags = 3; +} + +// Entities + +message ViewId { + PeerId creator = 1; + uint64 id = 2; +} + +message UpdateActiveView { + optional ViewId id = 1; + optional PeerId leader_id = 2; +} + +message UpdateView { + ViewId id = 1; + optional PeerId leader_id = 2; + + oneof variant { + Editor editor = 3; + } + + message Editor { + repeated ExcerptInsertion inserted_excerpts = 1; + repeated uint64 deleted_excerpts = 2; + repeated Selection selections = 3; + optional Selection pending_selection = 4; + EditorAnchor scroll_top_anchor = 5; + float scroll_x = 6; + float scroll_y = 7; + } +} + +message View { + ViewId id = 1; + optional PeerId leader_id = 2; + + oneof variant { + Editor editor = 3; + ChannelView channel_view = 4; + } + + message Editor { + bool singleton = 1; + optional string title = 2; + repeated Excerpt excerpts = 3; + repeated Selection selections = 4; + optional Selection pending_selection = 5; + EditorAnchor scroll_top_anchor = 6; + float scroll_x = 7; + float scroll_y = 8; + } + + message ChannelView { + uint64 channel_id = 1; + Editor editor = 2; + } +} + +message Collaborator { + PeerId peer_id = 1; + uint32 replica_id = 2; + uint64 user_id = 3; +} + +message User { + uint64 id = 1; + string github_login = 2; + string avatar_url = 3; +} + +message File { + uint64 worktree_id = 1; + uint64 entry_id = 2; + string path = 3; + Timestamp mtime = 4; + bool is_deleted = 5; +} + +message Entry { + uint64 id = 1; + bool is_dir = 2; + string path = 3; + uint64 inode = 4; + Timestamp mtime = 5; + bool is_symlink = 6; + bool is_ignored = 7; + bool is_external = 8; + optional GitStatus git_status = 9; +} + +message RepositoryEntry { + uint64 work_directory_id = 1; + optional string branch = 2; +} + +message StatusEntry { + string repo_path = 1; + GitStatus status = 2; +} + +enum GitStatus { + Added = 0; + Modified = 1; + Conflict = 2; +} + +message BufferState { + uint64 id = 1; + optional File file = 2; + string base_text = 3; + optional string diff_base = 4; + LineEnding line_ending = 5; + repeated VectorClockEntry saved_version = 6; + string saved_version_fingerprint = 7; + Timestamp saved_mtime = 8; +} + +message BufferChunk { + uint64 buffer_id = 1; + repeated Operation operations = 2; + bool is_last = 3; +} + +enum LineEnding { + Unix = 0; + Windows = 1; +} + +message Selection { + uint64 id = 1; + EditorAnchor start = 2; + EditorAnchor end = 3; + bool reversed = 4; +} + +message EditorAnchor { + uint64 excerpt_id = 1; + Anchor anchor = 2; +} + +enum CursorShape { + CursorBar = 0; + CursorBlock = 1; + CursorUnderscore = 2; + CursorHollow = 3; +} + +message ExcerptInsertion { + Excerpt excerpt = 1; + optional uint64 previous_excerpt_id = 2; +} + +message Excerpt { + uint64 id = 1; + uint64 buffer_id = 2; + Anchor context_start = 3; + Anchor context_end = 4; + Anchor primary_start = 5; + Anchor primary_end = 6; +} + +message Anchor { + uint32 replica_id = 1; + uint32 timestamp = 2; + uint64 offset = 3; + Bias bias = 4; + optional uint64 buffer_id = 5; +} + +enum Bias { + Left = 0; + Right = 1; +} + +message Diagnostic { + Anchor start = 1; + Anchor end = 2; + optional string source = 3; + Severity severity = 4; + string message = 5; + optional string code = 6; + uint64 group_id = 7; + bool is_primary = 8; + bool is_valid = 9; + bool is_disk_based = 10; + bool is_unnecessary = 11; + + enum Severity { + None = 0; + Error = 1; + Warning = 2; + Information = 3; + Hint = 4; + } +} + +message Operation { + oneof variant { + Edit edit = 1; + Undo undo = 2; + UpdateSelections update_selections = 3; + UpdateDiagnostics update_diagnostics = 4; + UpdateCompletionTriggers update_completion_triggers = 5; + } + + message Edit { + uint32 replica_id = 1; + uint32 lamport_timestamp = 2; + repeated VectorClockEntry version = 3; + repeated Range ranges = 4; + repeated string new_text = 5; + } + + message Undo { + uint32 replica_id = 1; + uint32 lamport_timestamp = 2; + repeated VectorClockEntry version = 3; + repeated UndoCount counts = 4; + } + + message UpdateSelections { + uint32 replica_id = 1; + uint32 lamport_timestamp = 2; + repeated Selection selections = 3; + bool line_mode = 4; + CursorShape cursor_shape = 5; + } + + message UpdateCompletionTriggers { + uint32 replica_id = 1; + uint32 lamport_timestamp = 2; + repeated string triggers = 3; + } +} + +message UndoMapEntry { + uint32 replica_id = 1; + uint32 local_timestamp = 2; + repeated UndoCount counts = 3; +} + +message UndoCount { + uint32 replica_id = 1; + uint32 lamport_timestamp = 2; + uint32 count = 3; +} + +message VectorClockEntry { + uint32 replica_id = 1; + uint32 timestamp = 2; +} + +message Timestamp { + uint64 seconds = 1; + uint32 nanos = 2; +} + +message Range { + uint64 start = 1; + uint64 end = 2; +} + +message PointUtf16 { + uint32 row = 1; + uint32 column = 2; +} + +message Nonce { + uint64 upper_half = 1; + uint64 lower_half = 2; +} + +message Channel { + uint64 id = 1; + string name = 2; +} + +message Contact { + uint64 user_id = 1; + bool online = 2; + bool busy = 3; + bool should_notify = 4; +} + +message WorktreeMetadata { + uint64 id = 1; + string root_name = 2; + bool visible = 3; + string abs_path = 4; +} + +message UpdateDiffBase { + uint64 project_id = 1; + uint64 buffer_id = 2; + optional string diff_base = 3; +} diff --git a/crates/rpc2/src/auth.rs b/crates/rpc2/src/auth.rs new file mode 100644 index 0000000000..ac7bbcebec --- /dev/null +++ b/crates/rpc2/src/auth.rs @@ -0,0 +1,136 @@ +use anyhow::{Context, Result}; +use rand::{thread_rng, Rng as _}; +use rsa::{PublicKey as _, PublicKeyEncoding, RSAPrivateKey, RSAPublicKey}; +use std::convert::TryFrom; + +pub struct PublicKey(RSAPublicKey); + +pub struct PrivateKey(RSAPrivateKey); + +/// Generate a public and private key for asymmetric encryption. +pub fn keypair() -> Result<(PublicKey, PrivateKey)> { + let mut rng = thread_rng(); + let bits = 1024; + let private_key = RSAPrivateKey::new(&mut rng, bits)?; + let public_key = RSAPublicKey::from(&private_key); + Ok((PublicKey(public_key), PrivateKey(private_key))) +} + +/// Generate a random 64-character base64 string. +pub fn random_token() -> String { + let mut rng = thread_rng(); + let mut token_bytes = [0; 48]; + for byte in token_bytes.iter_mut() { + *byte = rng.gen(); + } + base64::encode_config(token_bytes, base64::URL_SAFE) +} + +impl PublicKey { + /// Convert a string to a base64-encoded string that can only be decoded with the corresponding + /// private key. + pub fn encrypt_string(&self, string: &str) -> Result { + let mut rng = thread_rng(); + let bytes = string.as_bytes(); + let encrypted_bytes = self + .0 + .encrypt(&mut rng, PADDING_SCHEME, bytes) + .context("failed to encrypt string with public key")?; + let encrypted_string = base64::encode_config(&encrypted_bytes, base64::URL_SAFE); + Ok(encrypted_string) + } +} + +impl PrivateKey { + /// Decrypt a base64-encoded string that was encrypted by the corresponding public key. + pub fn decrypt_string(&self, encrypted_string: &str) -> Result { + let encrypted_bytes = base64::decode_config(encrypted_string, base64::URL_SAFE) + .context("failed to base64-decode encrypted string")?; + let bytes = self + .0 + .decrypt(PADDING_SCHEME, &encrypted_bytes) + .context("failed to decrypt string with private key")?; + let string = String::from_utf8(bytes).context("decrypted content was not valid utf8")?; + Ok(string) + } +} + +impl TryFrom for String { + type Error = anyhow::Error; + fn try_from(key: PublicKey) -> Result { + let bytes = key.0.to_pkcs1().context("failed to serialize public key")?; + let string = base64::encode_config(&bytes, base64::URL_SAFE); + Ok(string) + } +} + +impl TryFrom for PublicKey { + type Error = anyhow::Error; + fn try_from(value: String) -> Result { + let bytes = base64::decode_config(&value, base64::URL_SAFE) + .context("failed to base64-decode public key string")?; + let key = Self(RSAPublicKey::from_pkcs1(&bytes).context("failed to parse public key")?); + Ok(key) + } +} + +const PADDING_SCHEME: rsa::PaddingScheme = rsa::PaddingScheme::PKCS1v15Encrypt; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_generate_encrypt_and_decrypt_token() { + // CLIENT: + // * generate a keypair for asymmetric encryption + // * serialize the public key to send it to the server. + let (public, private) = keypair().unwrap(); + let public_string = String::try_from(public).unwrap(); + assert_printable(&public_string); + + // SERVER: + // * parse the public key + // * generate a random token. + // * encrypt the token using the public key. + let public = PublicKey::try_from(public_string).unwrap(); + let token = random_token(); + let encrypted_token = public.encrypt_string(&token).unwrap(); + assert_eq!(token.len(), 64); + assert_ne!(encrypted_token, token); + assert_printable(&token); + assert_printable(&encrypted_token); + + // CLIENT: + // * decrypt the token using the private key. + let decrypted_token = private.decrypt_string(&encrypted_token).unwrap(); + assert_eq!(decrypted_token, token); + } + + #[test] + fn test_tokens_are_always_url_safe() { + for _ in 0..5 { + let token = random_token(); + let (public_key, _) = keypair().unwrap(); + let encrypted_token = public_key.encrypt_string(&token).unwrap(); + let public_key_str = String::try_from(public_key).unwrap(); + + assert_printable(&token); + assert_printable(&public_key_str); + assert_printable(&encrypted_token); + } + } + + fn assert_printable(token: &str) { + for c in token.chars() { + assert!( + c.is_ascii_graphic(), + "token {:?} has non-printable char {}", + token, + c + ); + assert_ne!(c, '/', "token {:?} is not URL-safe", token); + assert_ne!(c, '&', "token {:?} is not URL-safe", token); + } + } +} diff --git a/crates/rpc2/src/conn.rs b/crates/rpc2/src/conn.rs new file mode 100644 index 0000000000..450e36782e --- /dev/null +++ b/crates/rpc2/src/conn.rs @@ -0,0 +1,112 @@ +use async_tungstenite::tungstenite::Message as WebSocketMessage; +use futures::{SinkExt as _, StreamExt as _}; + +pub struct Connection { + pub(crate) tx: + Box>, + pub(crate) rx: Box< + dyn 'static + + Send + + Unpin + + futures::Stream>, + >, +} + +impl Connection { + pub fn new(stream: S) -> Self + where + S: 'static + + Send + + Unpin + + futures::Sink + + futures::Stream>, + { + let (tx, rx) = stream.split(); + Self { + tx: Box::new(tx), + rx: Box::new(rx), + } + } + + pub async fn send(&mut self, message: WebSocketMessage) -> Result<(), anyhow::Error> { + self.tx.send(message).await + } + + #[cfg(any(test, feature = "test-support"))] + pub fn in_memory( + executor: std::sync::Arc, + ) -> (Self, Self, std::sync::Arc) { + use std::sync::{ + atomic::{AtomicBool, Ordering::SeqCst}, + Arc, + }; + + let killed = Arc::new(AtomicBool::new(false)); + let (a_tx, a_rx) = channel(killed.clone(), executor.clone()); + let (b_tx, b_rx) = channel(killed.clone(), executor); + return ( + Self { tx: a_tx, rx: b_rx }, + Self { tx: b_tx, rx: a_rx }, + killed, + ); + + #[allow(clippy::type_complexity)] + fn channel( + killed: Arc, + executor: Arc, + ) -> ( + Box>, + Box>>, + ) { + use anyhow::anyhow; + use futures::channel::mpsc; + use std::io::{Error, ErrorKind}; + + let (tx, rx) = mpsc::unbounded::(); + + let tx = tx.sink_map_err(|error| anyhow!(error)).with({ + let killed = killed.clone(); + let executor = Arc::downgrade(&executor); + move |msg| { + let killed = killed.clone(); + let executor = executor.clone(); + Box::pin(async move { + if let Some(executor) = executor.upgrade() { + executor.simulate_random_delay().await; + } + + // Writes to a half-open TCP connection will error. + if killed.load(SeqCst) { + std::io::Result::Err(Error::new(ErrorKind::Other, "connection lost"))?; + } + + Ok(msg) + }) + } + }); + + let rx = rx.then({ + let killed = killed; + let executor = Arc::downgrade(&executor); + move |msg| { + let killed = killed.clone(); + let executor = executor.clone(); + Box::pin(async move { + if let Some(executor) = executor.upgrade() { + executor.simulate_random_delay().await; + } + + // Reads from a half-open TCP connection will hang. + if killed.load(SeqCst) { + futures::future::pending::<()>().await; + } + + Ok(msg) + }) + } + }); + + (Box::new(tx), Box::new(rx)) + } + } +} diff --git a/crates/rpc2/src/macros.rs b/crates/rpc2/src/macros.rs new file mode 100644 index 0000000000..89e605540d --- /dev/null +++ b/crates/rpc2/src/macros.rs @@ -0,0 +1,70 @@ +#[macro_export] +macro_rules! messages { + ($(($name:ident, $priority:ident)),* $(,)?) => { + pub fn build_typed_envelope(sender_id: ConnectionId, envelope: Envelope) -> Option> { + match envelope.payload { + $(Some(envelope::Payload::$name(payload)) => { + Some(Box::new(TypedEnvelope { + sender_id, + original_sender_id: envelope.original_sender_id.map(|original_sender| PeerId { + owner_id: original_sender.owner_id, + id: original_sender.id + }), + message_id: envelope.id, + payload, + })) + }, )* + _ => None + } + } + + $( + impl EnvelopedMessage for $name { + const NAME: &'static str = std::stringify!($name); + const PRIORITY: MessagePriority = MessagePriority::$priority; + + fn into_envelope( + self, + id: u32, + responding_to: Option, + original_sender_id: Option, + ) -> Envelope { + Envelope { + id, + responding_to, + original_sender_id, + payload: Some(envelope::Payload::$name(self)), + } + } + + fn from_envelope(envelope: Envelope) -> Option { + if let Some(envelope::Payload::$name(msg)) = envelope.payload { + Some(msg) + } else { + None + } + } + } + )* + }; +} + +#[macro_export] +macro_rules! request_messages { + ($(($request_name:ident, $response_name:ident)),* $(,)?) => { + $(impl RequestMessage for $request_name { + type Response = $response_name; + })* + }; +} + +#[macro_export] +macro_rules! entity_messages { + ($id_field:ident, $($name:ident),* $(,)?) => { + $(impl EntityMessage for $name { + fn remote_entity_id(&self) -> u64 { + self.$id_field + } + })* + }; +} diff --git a/crates/rpc2/src/peer.rs b/crates/rpc2/src/peer.rs new file mode 100644 index 0000000000..91b914f169 --- /dev/null +++ b/crates/rpc2/src/peer.rs @@ -0,0 +1,933 @@ +use super::{ + proto::{self, AnyTypedEnvelope, EnvelopedMessage, MessageStream, PeerId, RequestMessage}, + Connection, +}; +use anyhow::{anyhow, Context, Result}; +use collections::HashMap; +use futures::{ + channel::{mpsc, oneshot}, + stream::BoxStream, + FutureExt, SinkExt, StreamExt, TryFutureExt, +}; +use parking_lot::{Mutex, RwLock}; +use serde::{ser::SerializeStruct, Serialize}; +use std::{fmt, sync::atomic::Ordering::SeqCst}; +use std::{ + future::Future, + marker::PhantomData, + sync::{ + atomic::{self, AtomicU32}, + Arc, + }, + time::Duration, +}; +use tracing::instrument; + +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub struct ConnectionId { + pub owner_id: u32, + pub id: u32, +} + +impl Into for ConnectionId { + fn into(self) -> PeerId { + PeerId { + owner_id: self.owner_id, + id: self.id, + } + } +} + +impl From for ConnectionId { + fn from(peer_id: PeerId) -> Self { + Self { + owner_id: peer_id.owner_id, + id: peer_id.id, + } + } +} + +impl fmt::Display for ConnectionId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}/{}", self.owner_id, self.id) + } +} + +pub struct Receipt { + pub sender_id: ConnectionId, + pub message_id: u32, + payload_type: PhantomData, +} + +impl Clone for Receipt { + fn clone(&self) -> Self { + Self { + sender_id: self.sender_id, + message_id: self.message_id, + payload_type: PhantomData, + } + } +} + +impl Copy for Receipt {} + +#[derive(Clone, Debug)] +pub struct TypedEnvelope { + pub sender_id: ConnectionId, + pub original_sender_id: Option, + pub message_id: u32, + pub payload: T, +} + +impl TypedEnvelope { + pub fn original_sender_id(&self) -> Result { + self.original_sender_id + .ok_or_else(|| anyhow!("missing original_sender_id")) + } +} + +impl TypedEnvelope { + pub fn receipt(&self) -> Receipt { + Receipt { + sender_id: self.sender_id, + message_id: self.message_id, + payload_type: PhantomData, + } + } +} + +pub struct Peer { + epoch: AtomicU32, + pub connections: RwLock>, + next_connection_id: AtomicU32, +} + +#[derive(Clone, Serialize)] +pub struct ConnectionState { + #[serde(skip)] + outgoing_tx: mpsc::UnboundedSender, + next_message_id: Arc, + #[allow(clippy::type_complexity)] + #[serde(skip)] + response_channels: + Arc)>>>>>, +} + +const KEEPALIVE_INTERVAL: Duration = Duration::from_secs(1); +const WRITE_TIMEOUT: Duration = Duration::from_secs(2); +pub const RECEIVE_TIMEOUT: Duration = Duration::from_secs(10); + +impl Peer { + pub fn new(epoch: u32) -> Arc { + Arc::new(Self { + epoch: AtomicU32::new(epoch), + connections: Default::default(), + next_connection_id: Default::default(), + }) + } + + pub fn epoch(&self) -> u32 { + self.epoch.load(SeqCst) + } + + #[instrument(skip_all)] + pub fn add_connection( + self: &Arc, + connection: Connection, + create_timer: F, + ) -> ( + ConnectionId, + impl Future> + Send, + BoxStream<'static, Box>, + ) + where + F: Send + Fn(Duration) -> Fut, + Fut: Send + Future, + Out: Send, + { + // For outgoing messages, use an unbounded channel so that application code + // can always send messages without yielding. For incoming messages, use a + // bounded channel so that other peers will receive backpressure if they send + // messages faster than this peer can process them. + #[cfg(any(test, feature = "test-support"))] + const INCOMING_BUFFER_SIZE: usize = 1; + #[cfg(not(any(test, feature = "test-support")))] + const INCOMING_BUFFER_SIZE: usize = 64; + let (mut incoming_tx, incoming_rx) = mpsc::channel(INCOMING_BUFFER_SIZE); + let (outgoing_tx, mut outgoing_rx) = mpsc::unbounded(); + + let connection_id = ConnectionId { + owner_id: self.epoch.load(SeqCst), + id: self.next_connection_id.fetch_add(1, SeqCst), + }; + let connection_state = ConnectionState { + outgoing_tx, + next_message_id: Default::default(), + response_channels: Arc::new(Mutex::new(Some(Default::default()))), + }; + let mut writer = MessageStream::new(connection.tx); + let mut reader = MessageStream::new(connection.rx); + + let this = self.clone(); + let response_channels = connection_state.response_channels.clone(); + let handle_io = async move { + tracing::trace!(%connection_id, "handle io future: start"); + + let _end_connection = util::defer(|| { + response_channels.lock().take(); + this.connections.write().remove(&connection_id); + tracing::trace!(%connection_id, "handle io future: end"); + }); + + // Send messages on this frequency so the connection isn't closed. + let keepalive_timer = create_timer(KEEPALIVE_INTERVAL).fuse(); + futures::pin_mut!(keepalive_timer); + + // Disconnect if we don't receive messages at least this frequently. + let receive_timeout = create_timer(RECEIVE_TIMEOUT).fuse(); + futures::pin_mut!(receive_timeout); + + loop { + tracing::trace!(%connection_id, "outer loop iteration start"); + let read_message = reader.read().fuse(); + futures::pin_mut!(read_message); + + loop { + tracing::trace!(%connection_id, "inner loop iteration start"); + futures::select_biased! { + outgoing = outgoing_rx.next().fuse() => match outgoing { + Some(outgoing) => { + tracing::trace!(%connection_id, "outgoing rpc message: writing"); + futures::select_biased! { + result = writer.write(outgoing).fuse() => { + tracing::trace!(%connection_id, "outgoing rpc message: done writing"); + result.context("failed to write RPC message")?; + tracing::trace!(%connection_id, "keepalive interval: resetting after sending message"); + keepalive_timer.set(create_timer(KEEPALIVE_INTERVAL).fuse()); + } + _ = create_timer(WRITE_TIMEOUT).fuse() => { + tracing::trace!(%connection_id, "outgoing rpc message: writing timed out"); + Err(anyhow!("timed out writing message"))?; + } + } + } + None => { + tracing::trace!(%connection_id, "outgoing rpc message: channel closed"); + return Ok(()) + }, + }, + _ = keepalive_timer => { + tracing::trace!(%connection_id, "keepalive interval: pinging"); + futures::select_biased! { + result = writer.write(proto::Message::Ping).fuse() => { + tracing::trace!(%connection_id, "keepalive interval: done pinging"); + result.context("failed to send keepalive")?; + tracing::trace!(%connection_id, "keepalive interval: resetting after pinging"); + keepalive_timer.set(create_timer(KEEPALIVE_INTERVAL).fuse()); + } + _ = create_timer(WRITE_TIMEOUT).fuse() => { + tracing::trace!(%connection_id, "keepalive interval: pinging timed out"); + Err(anyhow!("timed out sending keepalive"))?; + } + } + } + incoming = read_message => { + let incoming = incoming.context("error reading rpc message from socket")?; + tracing::trace!(%connection_id, "incoming rpc message: received"); + tracing::trace!(%connection_id, "receive timeout: resetting"); + receive_timeout.set(create_timer(RECEIVE_TIMEOUT).fuse()); + if let proto::Message::Envelope(incoming) = incoming { + tracing::trace!(%connection_id, "incoming rpc message: processing"); + futures::select_biased! { + result = incoming_tx.send(incoming).fuse() => match result { + Ok(_) => { + tracing::trace!(%connection_id, "incoming rpc message: processed"); + } + Err(_) => { + tracing::trace!(%connection_id, "incoming rpc message: channel closed"); + return Ok(()) + } + }, + _ = create_timer(WRITE_TIMEOUT).fuse() => { + tracing::trace!(%connection_id, "incoming rpc message: processing timed out"); + Err(anyhow!("timed out processing incoming message"))? + } + } + } + break; + }, + _ = receive_timeout => { + tracing::trace!(%connection_id, "receive timeout: delay between messages too long"); + Err(anyhow!("delay between messages too long"))? + } + } + } + } + }; + + let response_channels = connection_state.response_channels.clone(); + self.connections + .write() + .insert(connection_id, connection_state); + + let incoming_rx = incoming_rx.filter_map(move |incoming| { + let response_channels = response_channels.clone(); + async move { + let message_id = incoming.id; + tracing::trace!(?incoming, "incoming message future: start"); + let _end = util::defer(move || { + tracing::trace!(%connection_id, message_id, "incoming message future: end"); + }); + + if let Some(responding_to) = incoming.responding_to { + tracing::trace!( + %connection_id, + message_id, + responding_to, + "incoming response: received" + ); + let channel = response_channels.lock().as_mut()?.remove(&responding_to); + if let Some(tx) = channel { + let requester_resumed = oneshot::channel(); + if let Err(error) = tx.send((incoming, requester_resumed.0)) { + tracing::trace!( + %connection_id, + message_id, + responding_to = responding_to, + ?error, + "incoming response: request future dropped", + ); + } + + tracing::trace!( + %connection_id, + message_id, + responding_to, + "incoming response: waiting to resume requester" + ); + let _ = requester_resumed.1.await; + tracing::trace!( + %connection_id, + message_id, + responding_to, + "incoming response: requester resumed" + ); + } else { + tracing::warn!( + %connection_id, + message_id, + responding_to, + "incoming response: unknown request" + ); + } + + None + } else { + tracing::trace!(%connection_id, message_id, "incoming message: received"); + proto::build_typed_envelope(connection_id, incoming).or_else(|| { + tracing::error!( + %connection_id, + message_id, + "unable to construct a typed envelope" + ); + None + }) + } + } + }); + (connection_id, handle_io, incoming_rx.boxed()) + } + + #[cfg(any(test, feature = "test-support"))] + pub fn add_test_connection( + self: &Arc, + connection: Connection, + executor: Arc, + ) -> ( + ConnectionId, + impl Future> + Send, + BoxStream<'static, Box>, + ) { + let executor = executor.clone(); + self.add_connection(connection, move |duration| executor.timer(duration)) + } + + pub fn disconnect(&self, connection_id: ConnectionId) { + self.connections.write().remove(&connection_id); + } + + pub fn reset(&self, epoch: u32) { + self.teardown(); + self.next_connection_id.store(0, SeqCst); + self.epoch.store(epoch, SeqCst); + } + + pub fn teardown(&self) { + self.connections.write().clear(); + } + + pub fn request( + &self, + receiver_id: ConnectionId, + request: T, + ) -> impl Future> { + self.request_internal(None, receiver_id, request) + .map_ok(|envelope| envelope.payload) + } + + pub fn request_envelope( + &self, + receiver_id: ConnectionId, + request: T, + ) -> impl Future>> { + self.request_internal(None, receiver_id, request) + } + + pub fn forward_request( + &self, + sender_id: ConnectionId, + receiver_id: ConnectionId, + request: T, + ) -> impl Future> { + self.request_internal(Some(sender_id), receiver_id, request) + .map_ok(|envelope| envelope.payload) + } + + pub fn request_internal( + &self, + original_sender_id: Option, + receiver_id: ConnectionId, + request: T, + ) -> impl Future>> { + let (tx, rx) = oneshot::channel(); + let send = self.connection_state(receiver_id).and_then(|connection| { + let message_id = connection.next_message_id.fetch_add(1, SeqCst); + connection + .response_channels + .lock() + .as_mut() + .ok_or_else(|| anyhow!("connection was closed"))? + .insert(message_id, tx); + connection + .outgoing_tx + .unbounded_send(proto::Message::Envelope(request.into_envelope( + message_id, + None, + original_sender_id.map(Into::into), + ))) + .map_err(|_| anyhow!("connection was closed"))?; + Ok(()) + }); + async move { + send?; + let (response, _barrier) = rx.await.map_err(|_| anyhow!("connection was closed"))?; + + if let Some(proto::envelope::Payload::Error(error)) = &response.payload { + Err(anyhow!( + "RPC request {} failed - {}", + T::NAME, + error.message + )) + } else { + Ok(TypedEnvelope { + message_id: response.id, + sender_id: receiver_id, + original_sender_id: response.original_sender_id, + payload: T::Response::from_envelope(response) + .ok_or_else(|| anyhow!("received response of the wrong type"))?, + }) + } + } + } + + pub fn send(&self, receiver_id: ConnectionId, message: T) -> Result<()> { + let connection = self.connection_state(receiver_id)?; + let message_id = connection + .next_message_id + .fetch_add(1, atomic::Ordering::SeqCst); + connection + .outgoing_tx + .unbounded_send(proto::Message::Envelope( + message.into_envelope(message_id, None, None), + ))?; + Ok(()) + } + + pub fn forward_send( + &self, + sender_id: ConnectionId, + receiver_id: ConnectionId, + message: T, + ) -> Result<()> { + let connection = self.connection_state(receiver_id)?; + let message_id = connection + .next_message_id + .fetch_add(1, atomic::Ordering::SeqCst); + connection + .outgoing_tx + .unbounded_send(proto::Message::Envelope(message.into_envelope( + message_id, + None, + Some(sender_id.into()), + )))?; + Ok(()) + } + + pub fn respond( + &self, + receipt: Receipt, + response: T::Response, + ) -> Result<()> { + let connection = self.connection_state(receipt.sender_id)?; + let message_id = connection + .next_message_id + .fetch_add(1, atomic::Ordering::SeqCst); + connection + .outgoing_tx + .unbounded_send(proto::Message::Envelope(response.into_envelope( + message_id, + Some(receipt.message_id), + None, + )))?; + Ok(()) + } + + pub fn respond_with_error( + &self, + receipt: Receipt, + response: proto::Error, + ) -> Result<()> { + let connection = self.connection_state(receipt.sender_id)?; + let message_id = connection + .next_message_id + .fetch_add(1, atomic::Ordering::SeqCst); + connection + .outgoing_tx + .unbounded_send(proto::Message::Envelope(response.into_envelope( + message_id, + Some(receipt.message_id), + None, + )))?; + Ok(()) + } + + pub fn respond_with_unhandled_message( + &self, + envelope: Box, + ) -> Result<()> { + let connection = self.connection_state(envelope.sender_id())?; + let response = proto::Error { + message: format!("message {} was not handled", envelope.payload_type_name()), + }; + let message_id = connection + .next_message_id + .fetch_add(1, atomic::Ordering::SeqCst); + connection + .outgoing_tx + .unbounded_send(proto::Message::Envelope(response.into_envelope( + message_id, + Some(envelope.message_id()), + None, + )))?; + Ok(()) + } + + fn connection_state(&self, connection_id: ConnectionId) -> Result { + let connections = self.connections.read(); + let connection = connections + .get(&connection_id) + .ok_or_else(|| anyhow!("no such connection: {}", connection_id))?; + Ok(connection.clone()) + } +} + +impl Serialize for Peer { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_struct("Peer", 2)?; + state.serialize_field("connections", &*self.connections.read())?; + state.end() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::TypedEnvelope; + use async_tungstenite::tungstenite::Message as WebSocketMessage; + use gpui::TestAppContext; + + #[ctor::ctor] + fn init_logger() { + if std::env::var("RUST_LOG").is_ok() { + env_logger::init(); + } + } + + #[gpui::test(iterations = 50)] + async fn test_request_response(cx: &mut TestAppContext) { + let executor = cx.foreground(); + + // create 2 clients connected to 1 server + let server = Peer::new(0); + let client1 = Peer::new(0); + let client2 = Peer::new(0); + + let (client1_to_server_conn, server_to_client_1_conn, _kill) = + Connection::in_memory(cx.background()); + let (client1_conn_id, io_task1, client1_incoming) = + client1.add_test_connection(client1_to_server_conn, cx.background()); + let (_, io_task2, server_incoming1) = + server.add_test_connection(server_to_client_1_conn, cx.background()); + + let (client2_to_server_conn, server_to_client_2_conn, _kill) = + Connection::in_memory(cx.background()); + let (client2_conn_id, io_task3, client2_incoming) = + client2.add_test_connection(client2_to_server_conn, cx.background()); + let (_, io_task4, server_incoming2) = + server.add_test_connection(server_to_client_2_conn, cx.background()); + + executor.spawn(io_task1).detach(); + executor.spawn(io_task2).detach(); + executor.spawn(io_task3).detach(); + executor.spawn(io_task4).detach(); + executor + .spawn(handle_messages(server_incoming1, server.clone())) + .detach(); + executor + .spawn(handle_messages(client1_incoming, client1.clone())) + .detach(); + executor + .spawn(handle_messages(server_incoming2, server.clone())) + .detach(); + executor + .spawn(handle_messages(client2_incoming, client2.clone())) + .detach(); + + assert_eq!( + client1 + .request(client1_conn_id, proto::Ping {},) + .await + .unwrap(), + proto::Ack {} + ); + + assert_eq!( + client2 + .request(client2_conn_id, proto::Ping {},) + .await + .unwrap(), + proto::Ack {} + ); + + assert_eq!( + client1 + .request(client1_conn_id, proto::Test { id: 1 },) + .await + .unwrap(), + proto::Test { id: 1 } + ); + + assert_eq!( + client2 + .request(client2_conn_id, proto::Test { id: 2 }) + .await + .unwrap(), + proto::Test { id: 2 } + ); + + client1.disconnect(client1_conn_id); + client2.disconnect(client1_conn_id); + + async fn handle_messages( + mut messages: BoxStream<'static, Box>, + peer: Arc, + ) -> Result<()> { + while let Some(envelope) = messages.next().await { + let envelope = envelope.into_any(); + if let Some(envelope) = envelope.downcast_ref::>() { + let receipt = envelope.receipt(); + peer.respond(receipt, proto::Ack {})? + } else if let Some(envelope) = envelope.downcast_ref::>() + { + peer.respond(envelope.receipt(), envelope.payload.clone())? + } else { + panic!("unknown message type"); + } + } + + Ok(()) + } + } + + #[gpui::test(iterations = 50)] + async fn test_order_of_response_and_incoming(cx: &mut TestAppContext) { + let executor = cx.foreground(); + let server = Peer::new(0); + let client = Peer::new(0); + + let (client_to_server_conn, server_to_client_conn, _kill) = + Connection::in_memory(cx.background()); + let (client_to_server_conn_id, io_task1, mut client_incoming) = + client.add_test_connection(client_to_server_conn, cx.background()); + let (server_to_client_conn_id, io_task2, mut server_incoming) = + server.add_test_connection(server_to_client_conn, cx.background()); + + executor.spawn(io_task1).detach(); + executor.spawn(io_task2).detach(); + + executor + .spawn(async move { + let request = server_incoming + .next() + .await + .unwrap() + .into_any() + .downcast::>() + .unwrap(); + + server + .send( + server_to_client_conn_id, + proto::Error { + message: "message 1".to_string(), + }, + ) + .unwrap(); + server + .send( + server_to_client_conn_id, + proto::Error { + message: "message 2".to_string(), + }, + ) + .unwrap(); + server.respond(request.receipt(), proto::Ack {}).unwrap(); + + // Prevent the connection from being dropped + server_incoming.next().await; + }) + .detach(); + + let events = Arc::new(Mutex::new(Vec::new())); + + let response = client.request(client_to_server_conn_id, proto::Ping {}); + let response_task = executor.spawn({ + let events = events.clone(); + async move { + response.await.unwrap(); + events.lock().push("response".to_string()); + } + }); + + executor + .spawn({ + let events = events.clone(); + async move { + let incoming1 = client_incoming + .next() + .await + .unwrap() + .into_any() + .downcast::>() + .unwrap(); + events.lock().push(incoming1.payload.message); + let incoming2 = client_incoming + .next() + .await + .unwrap() + .into_any() + .downcast::>() + .unwrap(); + events.lock().push(incoming2.payload.message); + + // Prevent the connection from being dropped + client_incoming.next().await; + } + }) + .detach(); + + response_task.await; + assert_eq!( + &*events.lock(), + &[ + "message 1".to_string(), + "message 2".to_string(), + "response".to_string() + ] + ); + } + + #[gpui::test(iterations = 50)] + async fn test_dropping_request_before_completion(cx: &mut TestAppContext) { + let executor = cx.foreground(); + let server = Peer::new(0); + let client = Peer::new(0); + + let (client_to_server_conn, server_to_client_conn, _kill) = + Connection::in_memory(cx.background()); + let (client_to_server_conn_id, io_task1, mut client_incoming) = + client.add_test_connection(client_to_server_conn, cx.background()); + let (server_to_client_conn_id, io_task2, mut server_incoming) = + server.add_test_connection(server_to_client_conn, cx.background()); + + executor.spawn(io_task1).detach(); + executor.spawn(io_task2).detach(); + + executor + .spawn(async move { + let request1 = server_incoming + .next() + .await + .unwrap() + .into_any() + .downcast::>() + .unwrap(); + let request2 = server_incoming + .next() + .await + .unwrap() + .into_any() + .downcast::>() + .unwrap(); + + server + .send( + server_to_client_conn_id, + proto::Error { + message: "message 1".to_string(), + }, + ) + .unwrap(); + server + .send( + server_to_client_conn_id, + proto::Error { + message: "message 2".to_string(), + }, + ) + .unwrap(); + server.respond(request1.receipt(), proto::Ack {}).unwrap(); + server.respond(request2.receipt(), proto::Ack {}).unwrap(); + + // Prevent the connection from being dropped + server_incoming.next().await; + }) + .detach(); + + let events = Arc::new(Mutex::new(Vec::new())); + + let request1 = client.request(client_to_server_conn_id, proto::Ping {}); + let request1_task = executor.spawn(request1); + let request2 = client.request(client_to_server_conn_id, proto::Ping {}); + let request2_task = executor.spawn({ + let events = events.clone(); + async move { + request2.await.unwrap(); + events.lock().push("response 2".to_string()); + } + }); + + executor + .spawn({ + let events = events.clone(); + async move { + let incoming1 = client_incoming + .next() + .await + .unwrap() + .into_any() + .downcast::>() + .unwrap(); + events.lock().push(incoming1.payload.message); + let incoming2 = client_incoming + .next() + .await + .unwrap() + .into_any() + .downcast::>() + .unwrap(); + events.lock().push(incoming2.payload.message); + + // Prevent the connection from being dropped + client_incoming.next().await; + } + }) + .detach(); + + // Allow the request to make some progress before dropping it. + cx.background().simulate_random_delay().await; + drop(request1_task); + + request2_task.await; + assert_eq!( + &*events.lock(), + &[ + "message 1".to_string(), + "message 2".to_string(), + "response 2".to_string() + ] + ); + } + + #[gpui::test(iterations = 50)] + async fn test_disconnect(cx: &mut TestAppContext) { + let executor = cx.foreground(); + + let (client_conn, mut server_conn, _kill) = Connection::in_memory(cx.background()); + + let client = Peer::new(0); + let (connection_id, io_handler, mut incoming) = + client.add_test_connection(client_conn, cx.background()); + + let (io_ended_tx, io_ended_rx) = oneshot::channel(); + executor + .spawn(async move { + io_handler.await.ok(); + io_ended_tx.send(()).unwrap(); + }) + .detach(); + + let (messages_ended_tx, messages_ended_rx) = oneshot::channel(); + executor + .spawn(async move { + incoming.next().await; + messages_ended_tx.send(()).unwrap(); + }) + .detach(); + + client.disconnect(connection_id); + + let _ = io_ended_rx.await; + let _ = messages_ended_rx.await; + assert!(server_conn + .send(WebSocketMessage::Binary(vec![])) + .await + .is_err()); + } + + #[gpui::test(iterations = 50)] + async fn test_io_error(cx: &mut TestAppContext) { + let executor = cx.foreground(); + let (client_conn, mut server_conn, _kill) = Connection::in_memory(cx.background()); + + let client = Peer::new(0); + let (connection_id, io_handler, mut incoming) = + client.add_test_connection(client_conn, cx.background()); + executor.spawn(io_handler).detach(); + executor + .spawn(async move { incoming.next().await }) + .detach(); + + let response = executor.spawn(client.request(connection_id, proto::Ping {})); + let _request = server_conn.rx.next().await.unwrap().unwrap(); + + drop(server_conn); + assert_eq!( + response.await.unwrap_err().to_string(), + "connection was closed" + ); + } +} diff --git a/crates/rpc2/src/proto.rs b/crates/rpc2/src/proto.rs new file mode 100644 index 0000000000..f0d7937f6f --- /dev/null +++ b/crates/rpc2/src/proto.rs @@ -0,0 +1,674 @@ +#![allow(non_snake_case)] + +use super::{entity_messages, messages, request_messages, ConnectionId, TypedEnvelope}; +use anyhow::{anyhow, Result}; +use async_tungstenite::tungstenite::Message as WebSocketMessage; +use collections::HashMap; +use futures::{SinkExt as _, StreamExt as _}; +use prost::Message as _; +use serde::Serialize; +use std::any::{Any, TypeId}; +use std::{ + cmp, + fmt::Debug, + io, iter, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; +use std::{fmt, mem}; + +include!(concat!(env!("OUT_DIR"), "/zed.messages.rs")); + +pub trait EnvelopedMessage: Clone + Debug + Serialize + Sized + Send + Sync + 'static { + const NAME: &'static str; + const PRIORITY: MessagePriority; + fn into_envelope( + self, + id: u32, + responding_to: Option, + original_sender_id: Option, + ) -> Envelope; + fn from_envelope(envelope: Envelope) -> Option; +} + +pub trait EntityMessage: EnvelopedMessage { + fn remote_entity_id(&self) -> u64; +} + +pub trait RequestMessage: EnvelopedMessage { + type Response: EnvelopedMessage; +} + +pub trait AnyTypedEnvelope: 'static + Send + Sync { + fn payload_type_id(&self) -> TypeId; + fn payload_type_name(&self) -> &'static str; + fn as_any(&self) -> &dyn Any; + fn into_any(self: Box) -> Box; + fn is_background(&self) -> bool; + fn original_sender_id(&self) -> Option; + fn sender_id(&self) -> ConnectionId; + fn message_id(&self) -> u32; +} + +pub enum MessagePriority { + Foreground, + Background, +} + +impl AnyTypedEnvelope for TypedEnvelope { + fn payload_type_id(&self) -> TypeId { + TypeId::of::() + } + + fn payload_type_name(&self) -> &'static str { + T::NAME + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn into_any(self: Box) -> Box { + self + } + + fn is_background(&self) -> bool { + matches!(T::PRIORITY, MessagePriority::Background) + } + + fn original_sender_id(&self) -> Option { + self.original_sender_id + } + + fn sender_id(&self) -> ConnectionId { + self.sender_id + } + + fn message_id(&self) -> u32 { + self.message_id + } +} + +impl PeerId { + pub fn from_u64(peer_id: u64) -> Self { + let owner_id = (peer_id >> 32) as u32; + let id = peer_id as u32; + Self { owner_id, id } + } + + pub fn as_u64(self) -> u64 { + ((self.owner_id as u64) << 32) | (self.id as u64) + } +} + +impl Copy for PeerId {} + +impl Eq for PeerId {} + +impl Ord for PeerId { + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.owner_id + .cmp(&other.owner_id) + .then_with(|| self.id.cmp(&other.id)) + } +} + +impl PartialOrd for PeerId { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl std::hash::Hash for PeerId { + fn hash(&self, state: &mut H) { + self.owner_id.hash(state); + self.id.hash(state); + } +} + +impl fmt::Display for PeerId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}/{}", self.owner_id, self.id) + } +} + +messages!( + (Ack, Foreground), + (AddProjectCollaborator, Foreground), + (ApplyCodeAction, Background), + (ApplyCodeActionResponse, Background), + (ApplyCompletionAdditionalEdits, Background), + (ApplyCompletionAdditionalEditsResponse, Background), + (BufferReloaded, Foreground), + (BufferSaved, Foreground), + (Call, Foreground), + (CallCanceled, Foreground), + (CancelCall, Foreground), + (CopyProjectEntry, Foreground), + (CreateBufferForPeer, Foreground), + (CreateChannel, Foreground), + (CreateChannelResponse, Foreground), + (ChannelMessageSent, Foreground), + (CreateProjectEntry, Foreground), + (CreateRoom, Foreground), + (CreateRoomResponse, Foreground), + (DeclineCall, Foreground), + (DeleteProjectEntry, Foreground), + (Error, Foreground), + (ExpandProjectEntry, Foreground), + (Follow, Foreground), + (FollowResponse, Foreground), + (FormatBuffers, Foreground), + (FormatBuffersResponse, Foreground), + (FuzzySearchUsers, Foreground), + (GetCodeActions, Background), + (GetCodeActionsResponse, Background), + (GetHover, Background), + (GetHoverResponse, Background), + (GetChannelMessages, Background), + (GetChannelMessagesResponse, Background), + (SendChannelMessage, Background), + (SendChannelMessageResponse, Background), + (GetCompletions, Background), + (GetCompletionsResponse, Background), + (GetDefinition, Background), + (GetDefinitionResponse, Background), + (GetTypeDefinition, Background), + (GetTypeDefinitionResponse, Background), + (GetDocumentHighlights, Background), + (GetDocumentHighlightsResponse, Background), + (GetReferences, Background), + (GetReferencesResponse, Background), + (GetProjectSymbols, Background), + (GetProjectSymbolsResponse, Background), + (GetUsers, Foreground), + (Hello, Foreground), + (IncomingCall, Foreground), + (InviteChannelMember, Foreground), + (UsersResponse, Foreground), + (JoinProject, Foreground), + (JoinProjectResponse, Foreground), + (JoinRoom, Foreground), + (JoinRoomResponse, Foreground), + (JoinChannelChat, Foreground), + (JoinChannelChatResponse, Foreground), + (LeaveChannelChat, Foreground), + (LeaveProject, Foreground), + (LeaveRoom, Foreground), + (OpenBufferById, Background), + (OpenBufferByPath, Background), + (OpenBufferForSymbol, Background), + (OpenBufferForSymbolResponse, Background), + (OpenBufferResponse, Background), + (PerformRename, Background), + (PerformRenameResponse, Background), + (OnTypeFormatting, Background), + (OnTypeFormattingResponse, Background), + (InlayHints, Background), + (InlayHintsResponse, Background), + (ResolveInlayHint, Background), + (ResolveInlayHintResponse, Background), + (RefreshInlayHints, Foreground), + (Ping, Foreground), + (PrepareRename, Background), + (PrepareRenameResponse, Background), + (ExpandProjectEntryResponse, Foreground), + (ProjectEntryResponse, Foreground), + (RejoinRoom, Foreground), + (RejoinRoomResponse, Foreground), + (RemoveContact, Foreground), + (RemoveChannelMember, Foreground), + (RemoveChannelMessage, Foreground), + (ReloadBuffers, Foreground), + (ReloadBuffersResponse, Foreground), + (RemoveProjectCollaborator, Foreground), + (RenameProjectEntry, Foreground), + (RequestContact, Foreground), + (RespondToContactRequest, Foreground), + (RespondToChannelInvite, Foreground), + (JoinChannel, Foreground), + (RoomUpdated, Foreground), + (SaveBuffer, Foreground), + (RenameChannel, Foreground), + (RenameChannelResponse, Foreground), + (SetChannelMemberAdmin, Foreground), + (SearchProject, Background), + (SearchProjectResponse, Background), + (ShareProject, Foreground), + (ShareProjectResponse, Foreground), + (ShowContacts, Foreground), + (StartLanguageServer, Foreground), + (SynchronizeBuffers, Foreground), + (SynchronizeBuffersResponse, Foreground), + (RejoinChannelBuffers, Foreground), + (RejoinChannelBuffersResponse, Foreground), + (Test, Foreground), + (Unfollow, Foreground), + (UnshareProject, Foreground), + (UpdateBuffer, Foreground), + (UpdateBufferFile, Foreground), + (UpdateContacts, Foreground), + (DeleteChannel, Foreground), + (MoveChannel, Foreground), + (LinkChannel, Foreground), + (UnlinkChannel, Foreground), + (UpdateChannels, Foreground), + (UpdateDiagnosticSummary, Foreground), + (UpdateFollowers, Foreground), + (UpdateInviteInfo, Foreground), + (UpdateLanguageServer, Foreground), + (UpdateParticipantLocation, Foreground), + (UpdateProject, Foreground), + (UpdateProjectCollaborator, Foreground), + (UpdateWorktree, Foreground), + (UpdateWorktreeSettings, Foreground), + (UpdateDiffBase, Foreground), + (GetPrivateUserInfo, Foreground), + (GetPrivateUserInfoResponse, Foreground), + (GetChannelMembers, Foreground), + (GetChannelMembersResponse, Foreground), + (JoinChannelBuffer, Foreground), + (JoinChannelBufferResponse, Foreground), + (LeaveChannelBuffer, Background), + (UpdateChannelBuffer, Foreground), + (UpdateChannelBufferCollaborators, Foreground), + (AckBufferOperation, Background), + (AckChannelMessage, Background), +); + +request_messages!( + (ApplyCodeAction, ApplyCodeActionResponse), + ( + ApplyCompletionAdditionalEdits, + ApplyCompletionAdditionalEditsResponse + ), + (Call, Ack), + (CancelCall, Ack), + (CopyProjectEntry, ProjectEntryResponse), + (CreateProjectEntry, ProjectEntryResponse), + (CreateRoom, CreateRoomResponse), + (CreateChannel, CreateChannelResponse), + (DeclineCall, Ack), + (DeleteProjectEntry, ProjectEntryResponse), + (ExpandProjectEntry, ExpandProjectEntryResponse), + (Follow, FollowResponse), + (FormatBuffers, FormatBuffersResponse), + (GetCodeActions, GetCodeActionsResponse), + (GetHover, GetHoverResponse), + (GetCompletions, GetCompletionsResponse), + (GetDefinition, GetDefinitionResponse), + (GetTypeDefinition, GetTypeDefinitionResponse), + (GetDocumentHighlights, GetDocumentHighlightsResponse), + (GetReferences, GetReferencesResponse), + (GetPrivateUserInfo, GetPrivateUserInfoResponse), + (GetProjectSymbols, GetProjectSymbolsResponse), + (FuzzySearchUsers, UsersResponse), + (GetUsers, UsersResponse), + (InviteChannelMember, Ack), + (JoinProject, JoinProjectResponse), + (JoinRoom, JoinRoomResponse), + (JoinChannelChat, JoinChannelChatResponse), + (LeaveRoom, Ack), + (RejoinRoom, RejoinRoomResponse), + (IncomingCall, Ack), + (OpenBufferById, OpenBufferResponse), + (OpenBufferByPath, OpenBufferResponse), + (OpenBufferForSymbol, OpenBufferForSymbolResponse), + (Ping, Ack), + (PerformRename, PerformRenameResponse), + (PrepareRename, PrepareRenameResponse), + (OnTypeFormatting, OnTypeFormattingResponse), + (InlayHints, InlayHintsResponse), + (ResolveInlayHint, ResolveInlayHintResponse), + (RefreshInlayHints, Ack), + (ReloadBuffers, ReloadBuffersResponse), + (RequestContact, Ack), + (RemoveChannelMember, Ack), + (RemoveContact, Ack), + (RespondToContactRequest, Ack), + (RespondToChannelInvite, Ack), + (SetChannelMemberAdmin, Ack), + (SendChannelMessage, SendChannelMessageResponse), + (GetChannelMessages, GetChannelMessagesResponse), + (GetChannelMembers, GetChannelMembersResponse), + (JoinChannel, JoinRoomResponse), + (RemoveChannelMessage, Ack), + (DeleteChannel, Ack), + (RenameProjectEntry, ProjectEntryResponse), + (RenameChannel, RenameChannelResponse), + (LinkChannel, Ack), + (UnlinkChannel, Ack), + (MoveChannel, Ack), + (SaveBuffer, BufferSaved), + (SearchProject, SearchProjectResponse), + (ShareProject, ShareProjectResponse), + (SynchronizeBuffers, SynchronizeBuffersResponse), + (RejoinChannelBuffers, RejoinChannelBuffersResponse), + (Test, Test), + (UpdateBuffer, Ack), + (UpdateParticipantLocation, Ack), + (UpdateProject, Ack), + (UpdateWorktree, Ack), + (JoinChannelBuffer, JoinChannelBufferResponse), + (LeaveChannelBuffer, Ack) +); + +entity_messages!( + project_id, + AddProjectCollaborator, + ApplyCodeAction, + ApplyCompletionAdditionalEdits, + BufferReloaded, + BufferSaved, + CopyProjectEntry, + CreateBufferForPeer, + CreateProjectEntry, + DeleteProjectEntry, + ExpandProjectEntry, + FormatBuffers, + GetCodeActions, + GetCompletions, + GetDefinition, + GetTypeDefinition, + GetDocumentHighlights, + GetHover, + GetReferences, + GetProjectSymbols, + JoinProject, + LeaveProject, + OpenBufferById, + OpenBufferByPath, + OpenBufferForSymbol, + PerformRename, + OnTypeFormatting, + InlayHints, + ResolveInlayHint, + RefreshInlayHints, + PrepareRename, + ReloadBuffers, + RemoveProjectCollaborator, + RenameProjectEntry, + SaveBuffer, + SearchProject, + StartLanguageServer, + SynchronizeBuffers, + UnshareProject, + UpdateBuffer, + UpdateBufferFile, + UpdateDiagnosticSummary, + UpdateLanguageServer, + UpdateProject, + UpdateProjectCollaborator, + UpdateWorktree, + UpdateWorktreeSettings, + UpdateDiffBase +); + +entity_messages!( + channel_id, + ChannelMessageSent, + UpdateChannelBuffer, + RemoveChannelMessage, + UpdateChannelBufferCollaborators, +); + +const KIB: usize = 1024; +const MIB: usize = KIB * 1024; +const MAX_BUFFER_LEN: usize = MIB; + +/// A stream of protobuf messages. +pub struct MessageStream { + stream: S, + encoding_buffer: Vec, +} + +#[allow(clippy::large_enum_variant)] +#[derive(Debug)] +pub enum Message { + Envelope(Envelope), + Ping, + Pong, +} + +impl MessageStream { + pub fn new(stream: S) -> Self { + Self { + stream, + encoding_buffer: Vec::new(), + } + } + + pub fn inner_mut(&mut self) -> &mut S { + &mut self.stream + } +} + +impl MessageStream +where + S: futures::Sink + Unpin, +{ + pub async fn write(&mut self, message: Message) -> Result<(), anyhow::Error> { + #[cfg(any(test, feature = "test-support"))] + const COMPRESSION_LEVEL: i32 = -7; + + #[cfg(not(any(test, feature = "test-support")))] + const COMPRESSION_LEVEL: i32 = 4; + + match message { + Message::Envelope(message) => { + self.encoding_buffer.reserve(message.encoded_len()); + message + .encode(&mut self.encoding_buffer) + .map_err(io::Error::from)?; + let buffer = + zstd::stream::encode_all(self.encoding_buffer.as_slice(), COMPRESSION_LEVEL) + .unwrap(); + + self.encoding_buffer.clear(); + self.encoding_buffer.shrink_to(MAX_BUFFER_LEN); + self.stream.send(WebSocketMessage::Binary(buffer)).await?; + } + Message::Ping => { + self.stream + .send(WebSocketMessage::Ping(Default::default())) + .await?; + } + Message::Pong => { + self.stream + .send(WebSocketMessage::Pong(Default::default())) + .await?; + } + } + + Ok(()) + } +} + +impl MessageStream +where + S: futures::Stream> + Unpin, +{ + pub async fn read(&mut self) -> Result { + while let Some(bytes) = self.stream.next().await { + match bytes? { + WebSocketMessage::Binary(bytes) => { + zstd::stream::copy_decode(bytes.as_slice(), &mut self.encoding_buffer).unwrap(); + let envelope = Envelope::decode(self.encoding_buffer.as_slice()) + .map_err(io::Error::from)?; + + self.encoding_buffer.clear(); + self.encoding_buffer.shrink_to(MAX_BUFFER_LEN); + return Ok(Message::Envelope(envelope)); + } + WebSocketMessage::Ping(_) => return Ok(Message::Ping), + WebSocketMessage::Pong(_) => return Ok(Message::Pong), + WebSocketMessage::Close(_) => break, + _ => {} + } + } + Err(anyhow!("connection closed")) + } +} + +impl From for SystemTime { + fn from(val: Timestamp) -> Self { + UNIX_EPOCH + .checked_add(Duration::new(val.seconds, val.nanos)) + .unwrap() + } +} + +impl From for Timestamp { + fn from(time: SystemTime) -> Self { + let duration = time.duration_since(UNIX_EPOCH).unwrap(); + Self { + seconds: duration.as_secs(), + nanos: duration.subsec_nanos(), + } + } +} + +impl From for Nonce { + fn from(nonce: u128) -> Self { + let upper_half = (nonce >> 64) as u64; + let lower_half = nonce as u64; + Self { + upper_half, + lower_half, + } + } +} + +impl From for u128 { + fn from(nonce: Nonce) -> Self { + let upper_half = (nonce.upper_half as u128) << 64; + let lower_half = nonce.lower_half as u128; + upper_half | lower_half + } +} + +pub fn split_worktree_update( + mut message: UpdateWorktree, + max_chunk_size: usize, +) -> impl Iterator { + let mut done_files = false; + + let mut repository_map = message + .updated_repositories + .into_iter() + .map(|repo| (repo.work_directory_id, repo)) + .collect::>(); + + iter::from_fn(move || { + if done_files { + return None; + } + + let updated_entries_chunk_size = cmp::min(message.updated_entries.len(), max_chunk_size); + let updated_entries: Vec<_> = message + .updated_entries + .drain(..updated_entries_chunk_size) + .collect(); + + let removed_entries_chunk_size = cmp::min(message.removed_entries.len(), max_chunk_size); + let removed_entries = message + .removed_entries + .drain(..removed_entries_chunk_size) + .collect(); + + done_files = message.updated_entries.is_empty() && message.removed_entries.is_empty(); + + let mut updated_repositories = Vec::new(); + + if !repository_map.is_empty() { + for entry in &updated_entries { + if let Some(repo) = repository_map.remove(&entry.id) { + updated_repositories.push(repo) + } + } + } + + let removed_repositories = if done_files { + mem::take(&mut message.removed_repositories) + } else { + Default::default() + }; + + if done_files { + updated_repositories.extend(mem::take(&mut repository_map).into_values()); + } + + Some(UpdateWorktree { + project_id: message.project_id, + worktree_id: message.worktree_id, + root_name: message.root_name.clone(), + abs_path: message.abs_path.clone(), + updated_entries, + removed_entries, + scan_id: message.scan_id, + is_last_update: done_files && message.is_last_update, + updated_repositories, + removed_repositories, + }) + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[gpui::test] + async fn test_buffer_size() { + let (tx, rx) = futures::channel::mpsc::unbounded(); + let mut sink = MessageStream::new(tx.sink_map_err(|_| anyhow!(""))); + sink.write(Message::Envelope(Envelope { + payload: Some(envelope::Payload::UpdateWorktree(UpdateWorktree { + root_name: "abcdefg".repeat(10), + ..Default::default() + })), + ..Default::default() + })) + .await + .unwrap(); + assert!(sink.encoding_buffer.capacity() <= MAX_BUFFER_LEN); + sink.write(Message::Envelope(Envelope { + payload: Some(envelope::Payload::UpdateWorktree(UpdateWorktree { + root_name: "abcdefg".repeat(1000000), + ..Default::default() + })), + ..Default::default() + })) + .await + .unwrap(); + assert!(sink.encoding_buffer.capacity() <= MAX_BUFFER_LEN); + + let mut stream = MessageStream::new(rx.map(anyhow::Ok)); + stream.read().await.unwrap(); + assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN); + stream.read().await.unwrap(); + assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN); + } + + #[gpui::test] + fn test_converting_peer_id_from_and_to_u64() { + let peer_id = PeerId { + owner_id: 10, + id: 3, + }; + assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id); + let peer_id = PeerId { + owner_id: u32::MAX, + id: 3, + }; + assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id); + let peer_id = PeerId { + owner_id: 10, + id: u32::MAX, + }; + assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id); + let peer_id = PeerId { + owner_id: u32::MAX, + id: u32::MAX, + }; + assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id); + } +} diff --git a/crates/rpc2/src/rpc.rs b/crates/rpc2/src/rpc.rs new file mode 100644 index 0000000000..942672b94b --- /dev/null +++ b/crates/rpc2/src/rpc.rs @@ -0,0 +1,9 @@ +pub mod auth; +mod conn; +mod peer; +pub mod proto; +pub use conn::Connection; +pub use peer::*; +mod macros; + +pub const PROTOCOL_VERSION: u32 = 64; From 927278e20d149d9c0c5024e435d10a0bb8d4a9d8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Oct 2023 11:49:36 +0200 Subject: [PATCH 10/24] Remove IntoAnyElement bound from Element trait --- crates/copilot2/src/sign_in.rs | 2 +- crates/storybook2/src/stories/kitchen_sink.rs | 2 +- crates/storybook2/src/stories/scroll.rs | 5 +++-- crates/storybook2/src/stories/z_index.rs | 4 ++-- crates/storybook2/src/storybook2.rs | 4 ++-- crates/ui2/src/components/assistant_panel.rs | 8 ++------ crates/ui2/src/components/breadcrumb.rs | 8 ++------ crates/ui2/src/components/buffer.rs | 12 ++++-------- crates/ui2/src/components/buffer_search.rs | 2 +- crates/ui2/src/components/chat_panel.rs | 10 +++------- crates/ui2/src/components/collab_panel.rs | 8 ++------ crates/ui2/src/components/command_palette.rs | 8 ++------ crates/ui2/src/components/context_menu.rs | 8 ++------ crates/ui2/src/components/copilot.rs | 8 ++------ crates/ui2/src/components/editor_pane.rs | 2 +- crates/ui2/src/components/facepile.rs | 8 ++------ crates/ui2/src/components/icon_button.rs | 2 +- crates/ui2/src/components/keybinding.rs | 10 +++------- .../ui2/src/components/language_selector.rs | 8 ++------ crates/ui2/src/components/list.rs | 19 ++++++++----------- crates/ui2/src/components/modal.rs | 2 +- crates/ui2/src/components/multi_buffer.rs | 8 ++------ .../ui2/src/components/notification_toast.rs | 2 +- .../ui2/src/components/notifications_panel.rs | 8 ++------ crates/ui2/src/components/palette.rs | 10 +++------- crates/ui2/src/components/panel.rs | 8 ++------ crates/ui2/src/components/panes.rs | 2 +- crates/ui2/src/components/player_stack.rs | 2 +- crates/ui2/src/components/project_panel.rs | 8 ++------ crates/ui2/src/components/recent_projects.rs | 8 ++------ crates/ui2/src/components/status_bar.rs | 10 +++++++--- crates/ui2/src/components/tab.rs | 8 ++------ crates/ui2/src/components/tab_bar.rs | 8 ++------ crates/ui2/src/components/terminal.rs | 8 ++------ crates/ui2/src/components/theme_selector.rs | 8 ++------ crates/ui2/src/components/title_bar.rs | 4 ++-- crates/ui2/src/components/toast.rs | 4 ++-- crates/ui2/src/components/toolbar.rs | 8 ++------ crates/ui2/src/components/traffic_lights.rs | 10 +++------- crates/ui2/src/components/workspace.rs | 2 +- crates/ui2/src/elements/avatar.rs | 8 ++------ crates/ui2/src/elements/button.rs | 14 +++----------- crates/ui2/src/elements/details.rs | 8 ++------ crates/ui2/src/elements/icon.rs | 8 ++------ crates/ui2/src/elements/input.rs | 8 ++------ crates/ui2/src/elements/label.rs | 10 +++------- crates/ui2/src/elements/tool_divider.rs | 2 +- crates/ui2/src/story.rs | 6 +++--- 48 files changed, 106 insertions(+), 224 deletions(-) diff --git a/crates/copilot2/src/sign_in.rs b/crates/copilot2/src/sign_in.rs index ab326a8819..57f248aa52 100644 --- a/crates/copilot2/src/sign_in.rs +++ b/crates/copilot2/src/sign_in.rs @@ -106,7 +106,7 @@ // data: &PromptUserDeviceFlow, // style: &theme::Copilot, // cx: &mut ViewContext, -// ) -> impl Element { +// ) -> impl IntoAnyElement { // let copied = cx // .read_from_clipboard() // .map(|item| item.text() == &data.user_code) diff --git a/crates/storybook2/src/stories/kitchen_sink.rs b/crates/storybook2/src/stories/kitchen_sink.rs index 63cb1d0f51..fbb4f5099c 100644 --- a/crates/storybook2/src/stories/kitchen_sink.rs +++ b/crates/storybook2/src/stories/kitchen_sink.rs @@ -16,7 +16,7 @@ impl KitchenSinkStory { view(cx.entity(|cx| Self::new()), Self::render) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { let element_stories = ElementStory::iter() .map(|selector| selector.story(cx)) .collect::>(); diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs index 67200b52bc..f589ea7cef 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -1,6 +1,7 @@ use crate::themes::rose_pine; use gpui2::{ - div, px, view, Context, Element, ParentElement, SharedString, Styled, View, WindowContext, + div, px, view, Context, IntoAnyElement, ParentElement, SharedString, Styled, View, + WindowContext, }; use ui::ElementExt; @@ -16,7 +17,7 @@ impl ScrollStory { } } -fn checkerboard(depth: usize) -> impl Element +fn checkerboard(depth: usize) -> impl IntoAnyElement where S: 'static + Send + Sync, { diff --git a/crates/storybook2/src/stories/z_index.rs b/crates/storybook2/src/stories/z_index.rs index 39ac6fd6e4..213d7bed4e 100644 --- a/crates/storybook2/src/stories/z_index.rs +++ b/crates/storybook2/src/stories/z_index.rs @@ -19,7 +19,7 @@ impl ZIndexStory { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title(cx, "z-index")) .child( @@ -102,7 +102,7 @@ impl ZIndexExample { } } - fn render(&mut self, _view: &mut V, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut V, cx: &mut ViewContext) -> impl IntoAnyElement { div() .relative() .size_full() diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index 107d737ef9..4db1fd434b 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -10,7 +10,7 @@ use std::sync::Arc; use clap::Parser; use gpui2::{ - div, px, size, view, AnyView, AppContext, Bounds, Context, Element, ViewContext, WindowBounds, + div, px, size, view, AnyView, AppContext, Bounds, Context, ViewContext, WindowBounds, WindowOptions, }; use log::LevelFilter; @@ -107,7 +107,7 @@ impl StoryWrapper { Self { story, theme } } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { themed(self.theme.clone(), cx, |cx| { div() .flex() diff --git a/crates/ui2/src/components/assistant_panel.rs b/crates/ui2/src/components/assistant_panel.rs index 77d29f44f7..1c47bf1a91 100644 --- a/crates/ui2/src/components/assistant_panel.rs +++ b/crates/ui2/src/components/assistant_panel.rs @@ -26,7 +26,7 @@ impl AssistantPanel { self } - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Panel::new(self.id.clone(), cx) .children(vec![div() .flex() @@ -96,11 +96,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, AssistantPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/breadcrumb.rs b/crates/ui2/src/components/breadcrumb.rs index 4bd5283db3..5f4d3cbafe 100644 --- a/crates/ui2/src/components/breadcrumb.rs +++ b/crates/ui2/src/components/breadcrumb.rs @@ -31,11 +31,7 @@ impl Breadcrumb { div().child(" › ").text_color(theme.text_muted) } - fn render( - &mut self, - view_state: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, view_state: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let symbols_len = self.symbols.len(); @@ -106,7 +102,7 @@ mod stories { &mut self, view_state: &mut S, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl IntoAnyElement { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer.rs b/crates/ui2/src/components/buffer.rs index 51f5ea9196..7b67afc2b4 100644 --- a/crates/ui2/src/components/buffer.rs +++ b/crates/ui2/src/components/buffer.rs @@ -158,7 +158,7 @@ impl Buffer { self } - fn render_row(row: BufferRow, cx: &WindowContext) -> impl Element { + fn render_row(row: BufferRow, cx: &WindowContext) -> impl IntoAnyElement { let theme = theme(cx); let line_background = if row.current { @@ -208,7 +208,7 @@ impl Buffer { })) } - fn render_rows(&self, cx: &WindowContext) -> Vec> { + fn render_rows(&self, cx: &WindowContext) -> Vec> { match &self.rows { Some(rows) => rows .rows @@ -219,7 +219,7 @@ impl Buffer { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let rows = self.render_rows(cx); @@ -258,11 +258,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer_search.rs b/crates/ui2/src/components/buffer_search.rs index 3294aec780..e3e92aa073 100644 --- a/crates/ui2/src/components/buffer_search.rs +++ b/crates/ui2/src/components/buffer_search.rs @@ -25,7 +25,7 @@ impl BufferSearch { view(cx.entity(|cx| Self::new()), Self::render) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); h_stack().bg(theme.toolbar).p_2().child( diff --git a/crates/ui2/src/components/chat_panel.rs b/crates/ui2/src/components/chat_panel.rs index b66868138f..afb79cc907 100644 --- a/crates/ui2/src/components/chat_panel.rs +++ b/crates/ui2/src/components/chat_panel.rs @@ -24,7 +24,7 @@ impl ChatPanel { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .id(self.element_id.clone()) .flex() @@ -88,7 +88,7 @@ impl ChatMessage { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .flex() .flex_col() @@ -129,11 +129,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, ChatPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/collab_panel.rs b/crates/ui2/src/components/collab_panel.rs index 40276f20b3..d7dfcdceab 100644 --- a/crates/ui2/src/components/collab_panel.rs +++ b/crates/ui2/src/components/collab_panel.rs @@ -19,7 +19,7 @@ impl CollabPanel { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() @@ -110,11 +110,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, CollabPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/command_palette.rs b/crates/ui2/src/components/command_palette.rs index 036a41e0b9..b2418813d5 100644 --- a/crates/ui2/src/components/command_palette.rs +++ b/crates/ui2/src/components/command_palette.rs @@ -17,7 +17,7 @@ impl CommandPalette { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div().id(self.id.clone()).child( Palette::new("palette") .items(example_editor_actions()) @@ -49,11 +49,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, CommandPalette>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index fb076dc9fe..ea12cdcfc5 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -42,7 +42,7 @@ impl ContextMenu { items: items.into_iter().collect(), } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() @@ -85,11 +85,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, ContextMenu>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/copilot.rs b/crates/ui2/src/components/copilot.rs index 8c51b1f4eb..b1f41078e8 100644 --- a/crates/ui2/src/components/copilot.rs +++ b/crates/ui2/src/components/copilot.rs @@ -16,7 +16,7 @@ impl CopilotModal { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div().id(self.id.clone()).child( Modal::new("some-id") .title("Connect Copilot to Zed") @@ -47,11 +47,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, CopilotModal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/editor_pane.rs b/crates/ui2/src/components/editor_pane.rs index b641c86f7e..3fc41d7db6 100644 --- a/crates/ui2/src/components/editor_pane.rs +++ b/crates/ui2/src/components/editor_pane.rs @@ -49,7 +49,7 @@ impl EditorPane { ) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { v_stack() .w_full() .h_full() diff --git a/crates/ui2/src/components/facepile.rs b/crates/ui2/src/components/facepile.rs index b75ef328f3..0763b34b03 100644 --- a/crates/ui2/src/components/facepile.rs +++ b/crates/ui2/src/components/facepile.rs @@ -17,7 +17,7 @@ impl Facepile { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let player_count = self.players.len(); let player_list = self.players.iter().enumerate().map(|(ix, player)| { let isnt_last = ix < player_count - 1; @@ -51,11 +51,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let players = static_players(); Story::container(cx) diff --git a/crates/ui2/src/components/icon_button.rs b/crates/ui2/src/components/icon_button.rs index 77d248e9ee..6315842193 100644 --- a/crates/ui2/src/components/icon_button.rs +++ b/crates/ui2/src/components/icon_button.rs @@ -68,7 +68,7 @@ impl IconButton { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let icon_color = match (self.state, self.color) { diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index 25de760cab..78d05e4f30 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -34,7 +34,7 @@ impl Keybinding { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .flex() .gap_2() @@ -68,7 +68,7 @@ impl Key { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div() @@ -185,11 +185,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let all_modifier_permutations = ModifierKey::iter().permutations(2); Story::container(cx) diff --git a/crates/ui2/src/components/language_selector.rs b/crates/ui2/src/components/language_selector.rs index dbead8467e..0aea61b9a0 100644 --- a/crates/ui2/src/components/language_selector.rs +++ b/crates/ui2/src/components/language_selector.rs @@ -17,7 +17,7 @@ impl LanguageSelector { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div().id(self.id.clone()).child( Palette::new("palette") .items(vec![ @@ -60,11 +60,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, LanguageSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index 0c41671247..b7557b44d4 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -92,7 +92,7 @@ impl ListHeader { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let is_toggleable = self.toggleable != Toggleable::NotToggleable; @@ -157,7 +157,7 @@ impl ListSubHeader { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { h_stack().flex_1().w_full().relative().py_1().child( div() .h_6() @@ -230,7 +230,7 @@ impl From> for ListItem { } impl ListItem { - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { match self { ListItem::Entry(entry) => div().child(entry.render(view, cx)), ListItem::Separator(separator) => div().child(separator.render(view, cx)), @@ -344,10 +344,7 @@ impl ListEntry { } } - fn disclosure_control( - &mut self, - cx: &mut ViewContext, - ) -> Option> { + fn disclosure_control(&mut self, cx: &mut ViewContext) -> Option> { let disclosure_control_icon = if let Some(ToggleState::Toggled) = self.toggle { IconElement::new(Icon::ChevronDown) } else { @@ -367,7 +364,7 @@ impl ListEntry { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let settings = user_settings(cx); let theme = theme(cx); @@ -477,7 +474,7 @@ impl ListDetailsEntry { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let settings = user_settings(cx); @@ -534,7 +531,7 @@ impl ListSeparator { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div().h_px().w_full().bg(theme.border) @@ -574,7 +571,7 @@ impl List { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let is_toggleable = self.toggleable != Toggleable::NotToggleable; let is_toggled = Toggleable::is_toggled(&self.toggleable); diff --git a/crates/ui2/src/components/modal.rs b/crates/ui2/src/components/modal.rs index 154df4e862..63e7bc7c1a 100644 --- a/crates/ui2/src/components/modal.rs +++ b/crates/ui2/src/components/modal.rs @@ -42,7 +42,7 @@ impl Modal { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() diff --git a/crates/ui2/src/components/multi_buffer.rs b/crates/ui2/src/components/multi_buffer.rs index 568302b559..3bd3057d65 100644 --- a/crates/ui2/src/components/multi_buffer.rs +++ b/crates/ui2/src/components/multi_buffer.rs @@ -17,7 +17,7 @@ impl MultiBuffer { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() @@ -62,11 +62,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/notification_toast.rs b/crates/ui2/src/components/notification_toast.rs index afcef8fb20..cf68738a7e 100644 --- a/crates/ui2/src/components/notification_toast.rs +++ b/crates/ui2/src/components/notification_toast.rs @@ -28,7 +28,7 @@ impl NotificationToast { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); h_stack() diff --git a/crates/ui2/src/components/notifications_panel.rs b/crates/ui2/src/components/notifications_panel.rs index fd0445d007..1937c8e060 100644 --- a/crates/ui2/src/components/notifications_panel.rs +++ b/crates/ui2/src/components/notifications_panel.rs @@ -17,7 +17,7 @@ impl NotificationsPanel { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div() @@ -70,11 +70,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, NotificationsPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/palette.rs b/crates/ui2/src/components/palette.rs index 9787086cd6..b7cb7033bc 100644 --- a/crates/ui2/src/components/palette.rs +++ b/crates/ui2/src/components/palette.rs @@ -46,7 +46,7 @@ impl Palette { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() @@ -135,7 +135,7 @@ impl PaletteItem { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .flex() .flex_row() @@ -172,11 +172,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Palette>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index 0c52a7a12a..67b00d881b 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -96,7 +96,7 @@ impl Panel { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let current_size = self.width.unwrap_or(self.initial_width); @@ -148,11 +148,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Panel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index 229de3caa4..f100723f91 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -101,7 +101,7 @@ impl PaneGroup { } } - fn render(&mut self, view: &mut V, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, view: &mut V, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); if !self.panes.is_empty() { diff --git a/crates/ui2/src/components/player_stack.rs b/crates/ui2/src/components/player_stack.rs index 0ada98aa3f..6ca16d14e6 100644 --- a/crates/ui2/src/components/player_stack.rs +++ b/crates/ui2/src/components/player_stack.rs @@ -17,7 +17,7 @@ impl PlayerStack { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let player = self.player_with_call_status.get_player(); self.player_with_call_status.get_call_status(); diff --git a/crates/ui2/src/components/project_panel.rs b/crates/ui2/src/components/project_panel.rs index 8b52a1b89a..5a4591cadd 100644 --- a/crates/ui2/src/components/project_panel.rs +++ b/crates/ui2/src/components/project_panel.rs @@ -19,7 +19,7 @@ impl ProjectPanel { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div() @@ -79,11 +79,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, ProjectPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/recent_projects.rs b/crates/ui2/src/components/recent_projects.rs index 16c019be53..bab96444a5 100644 --- a/crates/ui2/src/components/recent_projects.rs +++ b/crates/ui2/src/components/recent_projects.rs @@ -17,7 +17,7 @@ impl RecentProjects { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div().id(self.id.clone()).child( Palette::new("palette") .items(vec![ @@ -56,11 +56,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, RecentProjects>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/status_bar.rs b/crates/ui2/src/components/status_bar.rs index 5eeeb841ef..786b3670a0 100644 --- a/crates/ui2/src/components/status_bar.rs +++ b/crates/ui2/src/components/status_bar.rs @@ -86,7 +86,7 @@ impl StatusBar { &mut self, view: &mut Workspace, cx: &mut ViewContext, - ) -> impl Element { + ) -> impl IntoAnyElement { let theme = theme(cx); div() @@ -101,7 +101,11 @@ impl StatusBar { .child(self.right_tools(view, cx)) } - fn left_tools(&self, workspace: &mut Workspace, cx: &WindowContext) -> impl Element { + fn left_tools( + &self, + workspace: &mut Workspace, + cx: &WindowContext, + ) -> impl IntoAnyElement { div() .flex() .items_center() @@ -132,7 +136,7 @@ impl StatusBar { &self, workspace: &mut Workspace, cx: &WindowContext, - ) -> impl Element { + ) -> impl IntoAnyElement { div() .flex() .items_center() diff --git a/crates/ui2/src/components/tab.rs b/crates/ui2/src/components/tab.rs index 4bfd21248f..daff5ea66c 100644 --- a/crates/ui2/src/components/tab.rs +++ b/crates/ui2/src/components/tab.rs @@ -81,7 +81,7 @@ impl Tab { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict; let is_deleted = self.fs_status == FileSystemStatus::Deleted; @@ -188,11 +188,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let git_statuses = GitStatus::iter(); let fs_statuses = FileSystemStatus::iter(); diff --git a/crates/ui2/src/components/tab_bar.rs b/crates/ui2/src/components/tab_bar.rs index 0cc9409c04..4e49ef289a 100644 --- a/crates/ui2/src/components/tab_bar.rs +++ b/crates/ui2/src/components/tab_bar.rs @@ -27,7 +27,7 @@ impl TabBar { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let (can_navigate_back, can_navigate_forward) = self.can_navigate; @@ -112,11 +112,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, TabBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/terminal.rs b/crates/ui2/src/components/terminal.rs index 480c1a5da6..2061d42ad2 100644 --- a/crates/ui2/src/components/terminal.rs +++ b/crates/ui2/src/components/terminal.rs @@ -17,7 +17,7 @@ impl Terminal { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let can_navigate_back = true; @@ -105,11 +105,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Terminal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/theme_selector.rs b/crates/ui2/src/components/theme_selector.rs index cb1b491d87..0758cf643b 100644 --- a/crates/ui2/src/components/theme_selector.rs +++ b/crates/ui2/src/components/theme_selector.rs @@ -17,7 +17,7 @@ impl ThemeSelector { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div().child( Palette::new(self.id.clone()) .items(vec![ @@ -61,11 +61,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, ThemeSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/title_bar.rs b/crates/ui2/src/components/title_bar.rs index 68661d0ea2..a20c7877b2 100644 --- a/crates/ui2/src/components/title_bar.rs +++ b/crates/ui2/src/components/title_bar.rs @@ -87,7 +87,7 @@ impl TitleBar { ) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let settings = user_settings(cx); @@ -204,7 +204,7 @@ mod stories { ) } - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, TitleBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/toast.rs b/crates/ui2/src/components/toast.rs index 9318b12eec..faf58467a2 100644 --- a/crates/ui2/src/components/toast.rs +++ b/crates/ui2/src/components/toast.rs @@ -36,7 +36,7 @@ impl Toast { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let mut div = div(); @@ -90,7 +90,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Toast>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/toolbar.rs b/crates/ui2/src/components/toolbar.rs index 51ec6ee497..74b2c92578 100644 --- a/crates/ui2/src/components/toolbar.rs +++ b/crates/ui2/src/components/toolbar.rs @@ -54,7 +54,7 @@ impl Toolbar { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div() @@ -92,11 +92,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/traffic_lights.rs b/crates/ui2/src/components/traffic_lights.rs index e875075942..8ac76439f8 100644 --- a/crates/ui2/src/components/traffic_lights.rs +++ b/crates/ui2/src/components/traffic_lights.rs @@ -25,7 +25,7 @@ impl TrafficLight { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let fill = match (self.window_has_focus, self.color) { @@ -58,7 +58,7 @@ impl TrafficLights { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .flex() .items_center() @@ -99,11 +99,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, TrafficLights>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index 92ea93ef02..34158c9918 100644 --- a/crates/ui2/src/components/workspace.rs +++ b/crates/ui2/src/components/workspace.rs @@ -174,7 +174,7 @@ impl Workspace { view(cx.entity(|cx| Self::new(cx)), Self::render) } - pub fn render(&mut self, cx: &mut ViewContext) -> impl Element { + pub fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = old_theme(cx).clone(); // HACK: This should happen inside of `debug_toggle_user_settings`, but diff --git a/crates/ui2/src/elements/avatar.rs b/crates/ui2/src/elements/avatar.rs index 0bc1ccad22..555818a87c 100644 --- a/crates/ui2/src/elements/avatar.rs +++ b/crates/ui2/src/elements/avatar.rs @@ -25,7 +25,7 @@ impl Avatar { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let mut img = img(); @@ -63,11 +63,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Avatar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index 363f70ddb4..9f399ea331 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -150,11 +150,7 @@ impl Button { self.icon.map(|i| IconElement::new(i).color(icon_color)) } - pub fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + pub fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let icon_color = self.icon_color(); let mut button = h_stack() @@ -211,7 +207,7 @@ impl ButtonGroup { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let mut el = h_stack().text_size(ui_size(cx, 1.)); for button in &mut self.buttons { @@ -246,11 +242,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let states = InteractionState::iter(); Story::container(cx) diff --git a/crates/ui2/src/elements/details.rs b/crates/ui2/src/elements/details.rs index e7df25f6a3..ea05436401 100644 --- a/crates/ui2/src/elements/details.rs +++ b/crates/ui2/src/elements/details.rs @@ -30,7 +30,7 @@ impl Details { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() @@ -66,11 +66,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Details>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/icon.rs b/crates/ui2/src/elements/icon.rs index d20f262fbc..2a0f6b3a0b 100644 --- a/crates/ui2/src/elements/icon.rs +++ b/crates/ui2/src/elements/icon.rs @@ -176,7 +176,7 @@ impl IconElement { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let fill = self.color.color(cx); let svg_size = match self.size { IconSize::Small => ui_size(cx, 12. / 14.), @@ -214,11 +214,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let icons = Icon::iter(); Story::container(cx) diff --git a/crates/ui2/src/elements/input.rs b/crates/ui2/src/elements/input.rs index 56d81a0831..142acc8870 100644 --- a/crates/ui2/src/elements/input.rs +++ b/crates/ui2/src/elements/input.rs @@ -60,7 +60,7 @@ impl Input { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let (input_bg, input_hover_bg, input_active_bg) = match self.variant { @@ -132,11 +132,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Input>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/label.rs b/crates/ui2/src/elements/label.rs index d29ab8a5ee..f8d4a8d115 100644 --- a/crates/ui2/src/elements/label.rs +++ b/crates/ui2/src/elements/label.rs @@ -83,7 +83,7 @@ impl Label { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .when(self.strikethrough, |this| { this.relative().child( @@ -135,7 +135,7 @@ impl HighlightedLabel { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let highlight_color = theme.text_accent; @@ -223,11 +223,7 @@ mod stories { } } - fn render( - &mut self, - _view: &mut S, - cx: &mut ViewContext, - ) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Label>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/tool_divider.rs b/crates/ui2/src/elements/tool_divider.rs index 46b790e6bb..f73c8953ee 100644 --- a/crates/ui2/src/elements/tool_divider.rs +++ b/crates/ui2/src/elements/tool_divider.rs @@ -14,7 +14,7 @@ impl ToolDivider { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { + fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div().w_px().h_3().bg(theme.border) diff --git a/crates/ui2/src/story.rs b/crates/ui2/src/story.rs index 9fc6a11f19..c4bf9c3caa 100644 --- a/crates/ui2/src/story.rs +++ b/crates/ui2/src/story.rs @@ -21,7 +21,7 @@ impl Story { pub fn title( cx: &mut ViewContext, title: &str, - ) -> impl Element { + ) -> impl IntoAnyElement { let theme = theme(cx); div() @@ -32,14 +32,14 @@ impl Story { pub fn title_for( cx: &mut ViewContext, - ) -> impl Element { + ) -> impl IntoAnyElement { Self::title(cx, std::any::type_name::()) } pub fn label( cx: &mut ViewContext, label: &str, - ) -> impl Element { + ) -> impl IntoAnyElement { let theme = theme(cx); div() From 315744ec20d8587219a7b052c2143d7495153e6b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Oct 2023 12:20:46 +0200 Subject: [PATCH 11/24] Add derive macro for IntoAnyElement --- .../src/derive_into_any_element.rs | 54 +++++++++++++++++++ crates/gpui2_macros/src/gpui2_macros.rs | 6 +++ crates/ui2/src/components/panes.rs | 13 ++--- crates/ui2/src/components/status_bar.rs | 15 ++++-- 4 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 crates/gpui2_macros/src/derive_into_any_element.rs diff --git a/crates/gpui2_macros/src/derive_into_any_element.rs b/crates/gpui2_macros/src/derive_into_any_element.rs new file mode 100644 index 0000000000..9f339f1b44 --- /dev/null +++ b/crates/gpui2_macros/src/derive_into_any_element.rs @@ -0,0 +1,54 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, DeriveInput}; + +pub fn derive_into_any_element(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + let name = &ast.ident; + let generics = &ast.generics; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let specified_view_type = ast + .attrs + .iter() + .find(|attr| attr.path.is_ident("element")) + .and_then(|attr| { + if let Ok(syn::Meta::List(meta_list)) = attr.parse_meta() { + meta_list.nested.iter().find_map(|nested| { + if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = nested { + if nv.path.is_ident("view_type") { + if let syn::Lit::Str(lit_str) = &nv.lit { + return Some( + lit_str + .parse::() + .expect("Failed to parse view_type"), + ); + } + } + } + None + }) + } else { + None + } + }); + + let view_type = specified_view_type.unwrap_or_else(|| { + if let Some(syn::GenericParam::Type(type_param)) = generics.params.first() { + type_param.ident.clone() + } else { + panic!("Expected first type parameter"); + } + }); + + let expanded = quote! { + impl #impl_generics gpui2::IntoAnyElement<#view_type> for #name #ty_generics #where_clause { + fn into_any(self) -> gpui2::AnyElement<#view_type> { + (move |view_state: &mut #view_type, cx: &mut gpui2::ViewContext<'_, '_, #view_type>| self.render(view_state, cx)) + .into_any() + } + } + }; + + TokenStream::from(expanded) +} diff --git a/crates/gpui2_macros/src/gpui2_macros.rs b/crates/gpui2_macros/src/gpui2_macros.rs index 59fd046c83..c4a3d5eeac 100644 --- a/crates/gpui2_macros/src/gpui2_macros.rs +++ b/crates/gpui2_macros/src/gpui2_macros.rs @@ -1,6 +1,7 @@ use proc_macro::TokenStream; mod derive_element; +mod derive_into_any_element; mod style_helpers; mod test; @@ -14,6 +15,11 @@ pub fn derive_element(input: TokenStream) -> TokenStream { derive_element::derive_element(input) } +#[proc_macro_derive(IntoAnyElement, attributes(element))] +pub fn derive_into_any_element(input: TokenStream) -> TokenStream { + derive_into_any_element::derive_into_any_element(input) +} + #[proc_macro_attribute] pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { test::test(args, function) diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index f100723f91..bf135d85b6 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -12,6 +12,7 @@ pub enum SplitDirection { Vertical, } +#[derive(IntoAnyElement)] pub struct Pane { id: ElementId, size: Size, @@ -19,12 +20,12 @@ pub struct Pane { children: SmallVec<[AnyElement; 2]>, } -impl IntoAnyElement for Pane { - fn into_any(self) -> AnyElement { - (move |view_state: &mut V, cx: &mut ViewContext<'_, '_, V>| self.render(view_state, cx)) - .into_any() - } -} +// impl IntoAnyElement for Pane { +// fn into_any(self) -> AnyElement { +// (move |view_state: &mut V, cx: &mut ViewContext<'_, '_, V>| self.render(view_state, cx)) +// .into_any() +// } +// } impl Pane { pub fn new(id: impl Into, size: Size) -> Self { diff --git a/crates/ui2/src/components/status_bar.rs b/crates/ui2/src/components/status_bar.rs index 786b3670a0..2e4399539c 100644 --- a/crates/ui2/src/components/status_bar.rs +++ b/crates/ui2/src/components/status_bar.rs @@ -28,14 +28,23 @@ impl Default for ToolGroup { } } -#[derive(Element)] -#[element(view_state = "Workspace")] +#[derive(IntoAnyElement)] +#[element(view_type = "Workspace")] pub struct StatusBar { left_tools: Option, right_tools: Option, bottom_tools: Option, } +// impl IntoAnyElement for StatusBar { +// fn into_any(self) -> gpui2::AnyElement { +// (move |workspace: &mut Workspace, cx: &mut ViewContext<'_, '_, Workspace>| { +// self.render(workspace, cx) +// }) +// .into_any() +// } +// } + impl StatusBar { pub fn new() -> Self { Self { @@ -83,7 +92,7 @@ impl StatusBar { } fn render( - &mut self, + self, view: &mut Workspace, cx: &mut ViewContext, ) -> impl IntoAnyElement { From 8ecfea55cd53fdc24f54764509945344424b8e9b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Oct 2023 12:38:23 +0200 Subject: [PATCH 12/24] Replace derive Element with derive IntoAnyElement everywhere --- crates/gpui2/src/element.rs | 10 ++ crates/gpui2_macros/src/derive_element.rs | 94 ------------------- crates/gpui2_macros/src/gpui2_macros.rs | 6 -- crates/storybook2/src/components.rs | 2 +- crates/storybook2/src/stories/scroll.rs | 1 - crates/storybook2/src/stories/z_index.rs | 8 +- crates/ui2/src/components/assistant_panel.rs | 8 +- crates/ui2/src/components/breadcrumb.rs | 12 +-- crates/ui2/src/components/buffer.rs | 8 +- crates/ui2/src/components/chat_panel.rs | 12 +-- crates/ui2/src/components/collab_panel.rs | 8 +- crates/ui2/src/components/command_palette.rs | 8 +- crates/ui2/src/components/context_menu.rs | 8 +- crates/ui2/src/components/copilot.rs | 8 +- crates/ui2/src/components/facepile.rs | 8 +- crates/ui2/src/components/icon_button.rs | 4 +- crates/ui2/src/components/keybinding.rs | 12 +-- .../ui2/src/components/language_selector.rs | 8 +- crates/ui2/src/components/list.rs | 28 +++--- crates/ui2/src/components/modal.rs | 4 +- crates/ui2/src/components/multi_buffer.rs | 8 +- .../ui2/src/components/notification_toast.rs | 4 +- .../ui2/src/components/notifications_panel.rs | 8 +- crates/ui2/src/components/palette.rs | 12 +-- crates/ui2/src/components/panel.rs | 8 +- crates/ui2/src/components/panes.rs | 6 +- crates/ui2/src/components/player_stack.rs | 4 +- crates/ui2/src/components/project_panel.rs | 8 +- crates/ui2/src/components/recent_projects.rs | 8 +- crates/ui2/src/components/status_bar.rs | 9 -- crates/ui2/src/components/tab.rs | 8 +- crates/ui2/src/components/tab_bar.rs | 8 +- crates/ui2/src/components/terminal.rs | 8 +- crates/ui2/src/components/theme_selector.rs | 8 +- crates/ui2/src/components/toast.rs | 10 +- crates/ui2/src/components/toolbar.rs | 8 +- crates/ui2/src/components/traffic_lights.rs | 12 +-- crates/ui2/src/element_ext.rs | 21 ++--- crates/ui2/src/elements/avatar.rs | 8 +- crates/ui2/src/elements/button.rs | 14 +-- crates/ui2/src/elements/details.rs | 8 +- crates/ui2/src/elements/icon.rs | 8 +- crates/ui2/src/elements/input.rs | 8 +- crates/ui2/src/elements/label.rs | 12 +-- crates/ui2/src/elements/tool_divider.rs | 4 +- 45 files changed, 185 insertions(+), 292 deletions(-) delete mode 100644 crates/gpui2_macros/src/derive_element.rs diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index 87e1e5c836..39b7898d16 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -209,6 +209,16 @@ impl AnyElement { pub trait IntoAnyElement { fn into_any(self) -> AnyElement; + + fn when(mut self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self + where + Self: Sized, + { + if condition { + self = then(self); + } + self + } } impl IntoAnyElement for AnyElement { diff --git a/crates/gpui2_macros/src/derive_element.rs b/crates/gpui2_macros/src/derive_element.rs deleted file mode 100644 index a63be0f5da..0000000000 --- a/crates/gpui2_macros/src/derive_element.rs +++ /dev/null @@ -1,94 +0,0 @@ -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, DeriveInput, GenericParam}; - -pub fn derive_element(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as DeriveInput); - let type_name = ast.ident; - - let mut state_type = quote! { () }; - - for param in &ast.generics.params { - if let GenericParam::Type(type_param) = param { - let type_ident = &type_param.ident; - state_type = quote! {#type_ident}; - break; - } - } - - let attrs = &ast.attrs; - for attr in attrs { - if attr.path.is_ident("element") { - match attr.parse_meta() { - Ok(syn::Meta::List(i)) => { - for nested_meta in i.nested { - if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = nested_meta { - if nv.path.is_ident("view_state") { - if let syn::Lit::Str(lit_str) = nv.lit { - state_type = lit_str.value().parse().unwrap(); - } - } - } - } - } - _ => (), - } - } - } - - let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); - - let gen = quote! { - impl #impl_generics gpui2::IntoAnyElement<#state_type> for #type_name #ty_generics - #where_clause - { - fn into_any(self) -> gpui2::AnyElement<#state_type> { - gpui2::AnyElement::new(self) - } - } - - impl #impl_generics gpui2::Element<#state_type> for #type_name #ty_generics - #where_clause - { - type ElementState = gpui2::AnyElement<#state_type>; - - fn id(&self) -> Option { - None - } - - fn initialize( - &mut self, - view_state: &mut #state_type, - _: Option, - cx: &mut gpui2::ViewContext<#state_type> - ) -> Self::ElementState { - use gpui2::IntoAnyElement; - - let mut element = self.render(view_state, cx).into_any(); - element.initialize(view_state, cx); - element - } - - fn layout( - &mut self, - view_state: &mut #state_type, - rendered_element: &mut Self::ElementState, - cx: &mut gpui2::ViewContext<#state_type>, - ) -> gpui2::LayoutId { - rendered_element.layout(view_state, cx) - } - - fn paint( - &mut self, - bounds: gpui2::Bounds, - view_state: &mut #state_type, - rendered_element: &mut Self::ElementState, - cx: &mut gpui2::ViewContext<#state_type>, - ) { - rendered_element.paint(view_state, cx) - } - } - }; - - gen.into() -} diff --git a/crates/gpui2_macros/src/gpui2_macros.rs b/crates/gpui2_macros/src/gpui2_macros.rs index c4a3d5eeac..3635320d55 100644 --- a/crates/gpui2_macros/src/gpui2_macros.rs +++ b/crates/gpui2_macros/src/gpui2_macros.rs @@ -1,6 +1,5 @@ use proc_macro::TokenStream; -mod derive_element; mod derive_into_any_element; mod style_helpers; mod test; @@ -10,11 +9,6 @@ pub fn style_helpers(args: TokenStream) -> TokenStream { style_helpers::style_helpers(args) } -#[proc_macro_derive(Element, attributes(element))] -pub fn derive_element(input: TokenStream) -> TokenStream { - derive_element::derive_element(input) -} - #[proc_macro_derive(IntoAnyElement, attributes(element))] pub fn derive_into_any_element(input: TokenStream) -> TokenStream { derive_into_any_element::derive_into_any_element(input) diff --git a/crates/storybook2/src/components.rs b/crates/storybook2/src/components.rs index c39ccaa3d9..5eaa894302 100644 --- a/crates/storybook2/src/components.rs +++ b/crates/storybook2/src/components.rs @@ -14,7 +14,7 @@ impl Default for ButtonHandlers { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Button { handlers: ButtonHandlers, label: Option>, diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs index f589ea7cef..86a8ca41c8 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -3,7 +3,6 @@ use gpui2::{ div, px, view, Context, IntoAnyElement, ParentElement, SharedString, Styled, View, WindowContext, }; -use ui::ElementExt; pub struct ScrollStory { text: View<()>, diff --git a/crates/storybook2/src/stories/z_index.rs b/crates/storybook2/src/stories/z_index.rs index 213d7bed4e..270bd08640 100644 --- a/crates/storybook2/src/stories/z_index.rs +++ b/crates/storybook2/src/stories/z_index.rs @@ -7,7 +7,7 @@ use crate::story::Story; /// A reimplementation of the MDN `z-index` example, found here: /// [https://developer.mozilla.org/en-US/docs/Web/CSS/z-index](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index). -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ZIndexStory { state_type: PhantomData, } @@ -19,7 +19,7 @@ impl ZIndexStory { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title(cx, "z-index")) .child( @@ -88,7 +88,7 @@ trait Styles: Styled + Sized { impl Styles for Div {} -#[derive(Element)] +#[derive(IntoAnyElement)] struct ZIndexExample { view_type: PhantomData, z_index: u32, @@ -102,7 +102,7 @@ impl ZIndexExample { } } - fn render(&mut self, _view: &mut V, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl IntoAnyElement { div() .relative() .size_full() diff --git a/crates/ui2/src/components/assistant_panel.rs b/crates/ui2/src/components/assistant_panel.rs index 1c47bf1a91..fa5ac38dc1 100644 --- a/crates/ui2/src/components/assistant_panel.rs +++ b/crates/ui2/src/components/assistant_panel.rs @@ -5,7 +5,7 @@ use gpui2::{rems, AbsoluteLength}; use crate::prelude::*; use crate::{Icon, IconButton, Label, Panel, PanelSide}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct AssistantPanel { id: ElementId, state_type: PhantomData, @@ -26,7 +26,7 @@ impl AssistantPanel { self } - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Panel::new(self.id.clone(), cx) .children(vec![div() .flex() @@ -84,7 +84,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct AssistantPanelStory { state_type: PhantomData, } @@ -96,7 +96,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, AssistantPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/breadcrumb.rs b/crates/ui2/src/components/breadcrumb.rs index 5f4d3cbafe..00a471e7cc 100644 --- a/crates/ui2/src/components/breadcrumb.rs +++ b/crates/ui2/src/components/breadcrumb.rs @@ -9,7 +9,7 @@ use crate::{h_stack, HighlightedText}; #[derive(Clone)] pub struct Symbol(pub Vec); -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Breadcrumb { state_type: PhantomData, path: PathBuf, @@ -31,7 +31,7 @@ impl Breadcrumb { div().child(" › ").text_color(theme.text_muted) } - fn render(&mut self, view_state: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, view_state: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let symbols_len = self.symbols.len(); @@ -86,7 +86,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct BreadcrumbStory { state_type: PhantomData, } @@ -98,11 +98,7 @@ mod stories { } } - fn render( - &mut self, - view_state: &mut S, - cx: &mut ViewContext, - ) -> impl IntoAnyElement { + fn render(self, view_state: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer.rs b/crates/ui2/src/components/buffer.rs index 7b67afc2b4..662ccd5736 100644 --- a/crates/ui2/src/components/buffer.rs +++ b/crates/ui2/src/components/buffer.rs @@ -109,7 +109,7 @@ impl BufferRow { } } -#[derive(Element, Clone)] +#[derive(IntoAnyElement, Clone)] pub struct Buffer { id: ElementId, state_type: PhantomData, @@ -219,7 +219,7 @@ impl Buffer { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let rows = self.render_rows(cx); @@ -246,7 +246,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct BufferStory { state_type: PhantomData, } @@ -258,7 +258,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/chat_panel.rs b/crates/ui2/src/components/chat_panel.rs index afb79cc907..db0f573485 100644 --- a/crates/ui2/src/components/chat_panel.rs +++ b/crates/ui2/src/components/chat_panel.rs @@ -5,7 +5,7 @@ use chrono::NaiveDateTime; use crate::prelude::*; use crate::{Icon, IconButton, Input, Label, LabelColor}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ChatPanel { element_id: ElementId, messages: Vec>, @@ -24,7 +24,7 @@ impl ChatPanel { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .id(self.element_id.clone()) .flex() @@ -70,7 +70,7 @@ impl ChatPanel { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ChatMessage { state_type: PhantomData, author: String, @@ -88,7 +88,7 @@ impl ChatMessage { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .flex() .flex_col() @@ -117,7 +117,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct ChatPanelStory { state_type: PhantomData, } @@ -129,7 +129,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, ChatPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/collab_panel.rs b/crates/ui2/src/components/collab_panel.rs index d7dfcdceab..050b7c2b85 100644 --- a/crates/ui2/src/components/collab_panel.rs +++ b/crates/ui2/src/components/collab_panel.rs @@ -5,7 +5,7 @@ use crate::{ }; use std::marker::PhantomData; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct CollabPanel { id: ElementId, state_type: PhantomData, @@ -19,7 +19,7 @@ impl CollabPanel { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() @@ -98,7 +98,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct CollabPanelStory { state_type: PhantomData, } @@ -110,7 +110,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, CollabPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/command_palette.rs b/crates/ui2/src/components/command_palette.rs index b2418813d5..f79038b172 100644 --- a/crates/ui2/src/components/command_palette.rs +++ b/crates/ui2/src/components/command_palette.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{example_editor_actions, OrderMethod, Palette}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct CommandPalette { id: ElementId, state_type: PhantomData, @@ -17,7 +17,7 @@ impl CommandPalette { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div().id(self.id.clone()).child( Palette::new("palette") .items(example_editor_actions()) @@ -37,7 +37,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct CommandPaletteStory { state_type: PhantomData, } @@ -49,7 +49,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, CommandPalette>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index ea12cdcfc5..5463cb29e7 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -31,7 +31,7 @@ impl ContextMenuItem { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ContextMenu { items: Vec>, } @@ -42,7 +42,7 @@ impl ContextMenu { items: items.into_iter().collect(), } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() @@ -73,7 +73,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct ContextMenuStory { state_type: PhantomData, } @@ -85,7 +85,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, ContextMenu>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/copilot.rs b/crates/ui2/src/components/copilot.rs index b1f41078e8..ca82ea5a0a 100644 --- a/crates/ui2/src/components/copilot.rs +++ b/crates/ui2/src/components/copilot.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::{prelude::*, Button, Label, LabelColor, Modal}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct CopilotModal { id: ElementId, state_type: PhantomData, @@ -16,7 +16,7 @@ impl CopilotModal { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div().id(self.id.clone()).child( Modal::new("some-id") .title("Connect Copilot to Zed") @@ -35,7 +35,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct CopilotModalStory { state_type: PhantomData, } @@ -47,7 +47,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, CopilotModal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/facepile.rs b/crates/ui2/src/components/facepile.rs index 0763b34b03..c87de6a2a2 100644 --- a/crates/ui2/src/components/facepile.rs +++ b/crates/ui2/src/components/facepile.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{Avatar, Player}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Facepile { state_type: PhantomData, players: Vec, @@ -17,7 +17,7 @@ impl Facepile { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let player_count = self.players.len(); let player_list = self.players.iter().enumerate().map(|(ix, player)| { let isnt_last = ix < player_count - 1; @@ -39,7 +39,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct FacepileStory { state_type: PhantomData, } @@ -51,7 +51,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let players = static_players(); Story::container(cx) diff --git a/crates/ui2/src/components/icon_button.rs b/crates/ui2/src/components/icon_button.rs index 6315842193..0801c5ac23 100644 --- a/crates/ui2/src/components/icon_button.rs +++ b/crates/ui2/src/components/icon_button.rs @@ -16,7 +16,7 @@ impl Default for IconButtonHandlers { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct IconButton { state_type: PhantomData, id: ElementId, @@ -68,7 +68,7 @@ impl IconButton { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let icon_color = match (self.state, self.color) { diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index 78d05e4f30..7a240aa39c 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -5,7 +5,7 @@ use strum::{EnumIter, IntoEnumIterator}; use crate::prelude::*; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Keybinding { state_type: PhantomData, @@ -34,7 +34,7 @@ impl Keybinding { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .flex() .gap_2() @@ -54,7 +54,7 @@ impl Keybinding { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Key { state_type: PhantomData, key: SharedString, @@ -68,7 +68,7 @@ impl Key { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div() @@ -173,7 +173,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct KeybindingStory { state_type: PhantomData, } @@ -185,7 +185,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let all_modifier_permutations = ModifierKey::iter().permutations(2); Story::container(cx) diff --git a/crates/ui2/src/components/language_selector.rs b/crates/ui2/src/components/language_selector.rs index 0aea61b9a0..5dd571ec42 100644 --- a/crates/ui2/src/components/language_selector.rs +++ b/crates/ui2/src/components/language_selector.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{OrderMethod, Palette, PaletteItem}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct LanguageSelector { id: ElementId, state_type: PhantomData, @@ -17,7 +17,7 @@ impl LanguageSelector { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div().id(self.id.clone()).child( Palette::new("palette") .items(vec![ @@ -48,7 +48,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct LanguageSelectorStory { state_type: PhantomData, } @@ -60,7 +60,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, LanguageSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index b7557b44d4..00684a7eb9 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -17,7 +17,7 @@ pub enum ListItemVariant { Inset, } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ListHeader { state_type: PhantomData, label: SharedString, @@ -92,7 +92,7 @@ impl ListHeader { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let is_toggleable = self.toggleable != Toggleable::NotToggleable; @@ -134,7 +134,7 @@ impl ListHeader { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ListSubHeader { state_type: PhantomData, label: SharedString, @@ -157,7 +157,7 @@ impl ListSubHeader { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { h_stack().flex_1().w_full().relative().py_1().child( div() .h_6() @@ -197,7 +197,7 @@ pub enum ListEntrySize { Medium, } -#[derive(Element)] +#[derive(IntoAnyElement)] pub enum ListItem { Entry(ListEntry), Details(ListDetailsEntry), @@ -230,7 +230,7 @@ impl From> for ListItem { } impl ListItem { - fn render(&mut self, view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { match self { ListItem::Entry(entry) => div().child(entry.render(view, cx)), ListItem::Separator(separator) => div().child(separator.render(view, cx)), @@ -252,7 +252,7 @@ impl ListItem { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ListEntry { disclosure_control_style: DisclosureControlVisibility, indent_level: u32, @@ -364,7 +364,7 @@ impl ListEntry { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let settings = user_settings(cx); let theme = theme(cx); @@ -430,7 +430,7 @@ impl Default for ListDetailsEntryHandlers { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ListDetailsEntry { label: SharedString, meta: Option, @@ -474,7 +474,7 @@ impl ListDetailsEntry { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let settings = user_settings(cx); @@ -519,7 +519,7 @@ impl ListDetailsEntry { } } -#[derive(Clone, Element)] +#[derive(Clone, IntoAnyElement)] pub struct ListSeparator { state_type: PhantomData, } @@ -531,14 +531,14 @@ impl ListSeparator { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div().h_px().w_full().bg(theme.border) } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct List { items: Vec>, empty_message: SharedString, @@ -571,7 +571,7 @@ impl List { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let is_toggleable = self.toggleable != Toggleable::NotToggleable; let is_toggled = Toggleable::is_toggled(&self.toggleable); diff --git a/crates/ui2/src/components/modal.rs b/crates/ui2/src/components/modal.rs index 63e7bc7c1a..c8fbfc0c6d 100644 --- a/crates/ui2/src/components/modal.rs +++ b/crates/ui2/src/components/modal.rs @@ -5,7 +5,7 @@ use smallvec::SmallVec; use crate::{h_stack, prelude::*, v_stack, Button, Icon, IconButton, Label}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Modal { id: ElementId, state_type: PhantomData, @@ -42,7 +42,7 @@ impl Modal { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() diff --git a/crates/ui2/src/components/multi_buffer.rs b/crates/ui2/src/components/multi_buffer.rs index 3bd3057d65..86e89c896c 100644 --- a/crates/ui2/src/components/multi_buffer.rs +++ b/crates/ui2/src/components/multi_buffer.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{v_stack, Buffer, Icon, IconButton, Label}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct MultiBuffer { state_type: PhantomData, buffers: Vec>, @@ -17,7 +17,7 @@ impl MultiBuffer { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() @@ -50,7 +50,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct MultiBufferStory { state_type: PhantomData, } @@ -62,7 +62,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/notification_toast.rs b/crates/ui2/src/components/notification_toast.rs index cf68738a7e..6a1011207b 100644 --- a/crates/ui2/src/components/notification_toast.rs +++ b/crates/ui2/src/components/notification_toast.rs @@ -4,7 +4,7 @@ use gpui2::rems; use crate::{h_stack, prelude::*, Icon}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct NotificationToast { state_type: PhantomData, label: SharedString, @@ -28,7 +28,7 @@ impl NotificationToast { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); h_stack() diff --git a/crates/ui2/src/components/notifications_panel.rs b/crates/ui2/src/components/notifications_panel.rs index 1937c8e060..44af3696c2 100644 --- a/crates/ui2/src/components/notifications_panel.rs +++ b/crates/ui2/src/components/notifications_panel.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::{prelude::*, static_new_notification_items, static_read_notification_items}; use crate::{List, ListHeader}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct NotificationsPanel { id: ElementId, state_type: PhantomData, @@ -17,7 +17,7 @@ impl NotificationsPanel { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div() @@ -58,7 +58,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct NotificationsPanelStory { state_type: PhantomData, } @@ -70,7 +70,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, NotificationsPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/palette.rs b/crates/ui2/src/components/palette.rs index b7cb7033bc..5b52f41aec 100644 --- a/crates/ui2/src/components/palette.rs +++ b/crates/ui2/src/components/palette.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{h_stack, v_stack, Keybinding, Label, LabelColor}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Palette { id: ElementId, state_type: PhantomData, @@ -46,7 +46,7 @@ impl Palette { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() @@ -101,7 +101,7 @@ impl Palette { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct PaletteItem { pub label: SharedString, pub sublabel: Option, @@ -135,7 +135,7 @@ impl PaletteItem { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .flex() .flex_row() @@ -160,7 +160,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct PaletteStory { state_type: PhantomData, } @@ -172,7 +172,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Palette>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index 67b00d881b..e6bca5afa7 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -40,7 +40,7 @@ pub enum PanelSide { use std::collections::HashSet; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Panel { id: ElementId, state_type: PhantomData, @@ -96,7 +96,7 @@ impl Panel { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let current_size = self.width.unwrap_or(self.initial_width); @@ -136,7 +136,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct PanelStory { state_type: PhantomData, } @@ -148,7 +148,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Panel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index bf135d85b6..118bb5f197 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -75,7 +75,7 @@ impl ParentElement for Pane { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct PaneGroup { state_type: PhantomData, groups: Vec>, @@ -102,7 +102,7 @@ impl PaneGroup { } } - fn render(&mut self, view: &mut V, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, view: &mut V, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); if !self.panes.is_empty() { @@ -129,7 +129,7 @@ impl PaneGroup { .w_full() .h_full() .bg(theme.editor) - .children(self.groups.iter_mut().map(|group| group.render(view, cx))); + .children(self.groups.drain(..).map(|group| group.render(view, cx))); if self.split_direction == SplitDirection::Horizontal { return el; diff --git a/crates/ui2/src/components/player_stack.rs b/crates/ui2/src/components/player_stack.rs index 6ca16d14e6..88b2833dda 100644 --- a/crates/ui2/src/components/player_stack.rs +++ b/crates/ui2/src/components/player_stack.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{Avatar, Facepile, PlayerWithCallStatus}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct PlayerStack { state_type: PhantomData, player_with_call_status: PlayerWithCallStatus, @@ -17,7 +17,7 @@ impl PlayerStack { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let player = self.player_with_call_status.get_player(); self.player_with_call_status.get_call_status(); diff --git a/crates/ui2/src/components/project_panel.rs b/crates/ui2/src/components/project_panel.rs index 5a4591cadd..5771f996c5 100644 --- a/crates/ui2/src/components/project_panel.rs +++ b/crates/ui2/src/components/project_panel.rs @@ -5,7 +5,7 @@ use crate::{ static_project_panel_project_items, static_project_panel_single_items, Input, List, ListHeader, }; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ProjectPanel { id: ElementId, state_type: PhantomData, @@ -19,7 +19,7 @@ impl ProjectPanel { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div() @@ -67,7 +67,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct ProjectPanelStory { state_type: PhantomData, } @@ -79,7 +79,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, ProjectPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/recent_projects.rs b/crates/ui2/src/components/recent_projects.rs index bab96444a5..d29caa2fd2 100644 --- a/crates/ui2/src/components/recent_projects.rs +++ b/crates/ui2/src/components/recent_projects.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{OrderMethod, Palette, PaletteItem}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct RecentProjects { id: ElementId, state_type: PhantomData, @@ -17,7 +17,7 @@ impl RecentProjects { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div().id(self.id.clone()).child( Palette::new("palette") .items(vec![ @@ -44,7 +44,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct RecentProjectsStory { state_type: PhantomData, } @@ -56,7 +56,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, RecentProjects>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/status_bar.rs b/crates/ui2/src/components/status_bar.rs index 2e4399539c..4ea0fe4eeb 100644 --- a/crates/ui2/src/components/status_bar.rs +++ b/crates/ui2/src/components/status_bar.rs @@ -36,15 +36,6 @@ pub struct StatusBar { bottom_tools: Option, } -// impl IntoAnyElement for StatusBar { -// fn into_any(self) -> gpui2::AnyElement { -// (move |workspace: &mut Workspace, cx: &mut ViewContext<'_, '_, Workspace>| { -// self.render(workspace, cx) -// }) -// .into_any() -// } -// } - impl StatusBar { pub fn new() -> Self { Self { diff --git a/crates/ui2/src/components/tab.rs b/crates/ui2/src/components/tab.rs index daff5ea66c..02a2420580 100644 --- a/crates/ui2/src/components/tab.rs +++ b/crates/ui2/src/components/tab.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{Icon, IconColor, IconElement, Label, LabelColor}; -#[derive(Element, Clone)] +#[derive(IntoAnyElement, Clone)] pub struct Tab { state_type: PhantomData, id: ElementId, @@ -81,7 +81,7 @@ impl Tab { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict; let is_deleted = self.fs_status == FileSystemStatus::Deleted; @@ -176,7 +176,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct TabStory { state_type: PhantomData, } @@ -188,7 +188,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let git_statuses = GitStatus::iter(); let fs_statuses = FileSystemStatus::iter(); diff --git a/crates/ui2/src/components/tab_bar.rs b/crates/ui2/src/components/tab_bar.rs index 4e49ef289a..38dd9edade 100644 --- a/crates/ui2/src/components/tab_bar.rs +++ b/crates/ui2/src/components/tab_bar.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{Icon, IconButton, Tab}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct TabBar { id: ElementId, state_type: PhantomData, @@ -27,7 +27,7 @@ impl TabBar { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let (can_navigate_back, can_navigate_forward) = self.can_navigate; @@ -100,7 +100,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct TabBarStory { state_type: PhantomData, } @@ -112,7 +112,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, TabBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/terminal.rs b/crates/ui2/src/components/terminal.rs index 2061d42ad2..55ab3e02fc 100644 --- a/crates/ui2/src/components/terminal.rs +++ b/crates/ui2/src/components/terminal.rs @@ -5,7 +5,7 @@ use gpui2::{relative, rems, Size}; use crate::prelude::*; use crate::{Icon, IconButton, Pane, Tab}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Terminal { state_type: PhantomData, } @@ -17,7 +17,7 @@ impl Terminal { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let can_navigate_back = true; @@ -93,7 +93,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct TerminalStory { state_type: PhantomData, } @@ -105,7 +105,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Terminal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/theme_selector.rs b/crates/ui2/src/components/theme_selector.rs index 0758cf643b..1851aea954 100644 --- a/crates/ui2/src/components/theme_selector.rs +++ b/crates/ui2/src/components/theme_selector.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{OrderMethod, Palette, PaletteItem}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ThemeSelector { id: ElementId, state_type: PhantomData, @@ -17,7 +17,7 @@ impl ThemeSelector { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div().child( Palette::new(self.id.clone()) .items(vec![ @@ -49,7 +49,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct ThemeSelectorStory { state_type: PhantomData, } @@ -61,7 +61,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, ThemeSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/toast.rs b/crates/ui2/src/components/toast.rs index faf58467a2..268042144b 100644 --- a/crates/ui2/src/components/toast.rs +++ b/crates/ui2/src/components/toast.rs @@ -22,7 +22,7 @@ pub enum ToastOrigin { /// they are actively showing the a process in progress. /// /// Only one toast may be visible at a time. -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Toast { origin: ToastOrigin, children: SmallVec<[AnyElement; 2]>, @@ -36,7 +36,7 @@ impl Toast { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let mut div = div(); @@ -57,7 +57,7 @@ impl Toast { .shadow_md() .overflow_hidden() .bg(theme.elevated_surface) - .children(self.children.drain(..)) + .children(self.children) } } @@ -78,7 +78,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct ToastStory { state_type: PhantomData, } @@ -90,7 +90,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Toast>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/toolbar.rs b/crates/ui2/src/components/toolbar.rs index 74b2c92578..e18c81314d 100644 --- a/crates/ui2/src/components/toolbar.rs +++ b/crates/ui2/src/components/toolbar.rs @@ -6,7 +6,7 @@ use crate::prelude::*; #[derive(Clone)] pub struct ToolbarItem {} -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Toolbar { left_items: SmallVec<[AnyElement; 2]>, right_items: SmallVec<[AnyElement; 2]>, @@ -54,7 +54,7 @@ impl Toolbar { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div() @@ -80,7 +80,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct ToolbarStory { state_type: PhantomData, } @@ -92,7 +92,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/traffic_lights.rs b/crates/ui2/src/components/traffic_lights.rs index 8ac76439f8..cfe589b463 100644 --- a/crates/ui2/src/components/traffic_lights.rs +++ b/crates/ui2/src/components/traffic_lights.rs @@ -9,7 +9,7 @@ enum TrafficLightColor { Green, } -#[derive(Element)] +#[derive(IntoAnyElement)] struct TrafficLight { state_type: PhantomData, color: TrafficLightColor, @@ -25,7 +25,7 @@ impl TrafficLight { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let fill = match (self.window_has_focus, self.color) { @@ -39,7 +39,7 @@ impl TrafficLight { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct TrafficLights { state_type: PhantomData, window_has_focus: bool, @@ -58,7 +58,7 @@ impl TrafficLights { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .flex() .items_center() @@ -87,7 +87,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct TrafficLightsStory { state_type: PhantomData, } @@ -99,7 +99,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, TrafficLights>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/element_ext.rs b/crates/ui2/src/element_ext.rs index 813f01dd24..fb31307d12 100644 --- a/crates/ui2/src/element_ext.rs +++ b/crates/ui2/src/element_ext.rs @@ -1,18 +1,15 @@ use gpui2::Element; pub trait ElementExt: Element { - /// Applies a given function `then` to the current element if `condition` is true. - /// This function is used to conditionally modify the element based on a given condition. - /// If `condition` is false, it just returns the current element as it is. - fn when(mut self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self - where - Self: Sized, - { - if condition { - self = then(self); - } - self - } + // fn when(mut self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self + // where + // Self: Sized, + // { + // if condition { + // self = then(self); + // } + // self + // } // fn when_some(mut self, option: Option, then: impl FnOnce(Self, T) -> U) -> U // where diff --git a/crates/ui2/src/elements/avatar.rs b/crates/ui2/src/elements/avatar.rs index 555818a87c..7d2e91ae8c 100644 --- a/crates/ui2/src/elements/avatar.rs +++ b/crates/ui2/src/elements/avatar.rs @@ -4,7 +4,7 @@ use gpui2::img; use crate::prelude::*; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Avatar { state_type: PhantomData, src: SharedString, @@ -25,7 +25,7 @@ impl Avatar { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let mut img = img(); @@ -51,7 +51,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct AvatarStory { state_type: PhantomData, } @@ -63,7 +63,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Avatar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index 9f399ea331..843a786aff 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -61,7 +61,7 @@ impl Default for ButtonHandlers { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Button { state_type: PhantomData, disabled: bool, @@ -150,7 +150,7 @@ impl Button { self.icon.map(|i| IconElement::new(i).color(icon_color)) } - pub fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + pub fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let icon_color = self.icon_color(); let mut button = h_stack() @@ -193,7 +193,7 @@ impl Button { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ButtonGroup { state_type: PhantomData, buttons: Vec>, @@ -207,10 +207,10 @@ impl ButtonGroup { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let mut el = h_stack().text_size(ui_size(cx, 1.)); - for button in &mut self.buttons { + for button in self.buttons { el = el.child(button.render(_view, cx)); } @@ -230,7 +230,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct ButtonStory { state_type: PhantomData, } @@ -242,7 +242,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let states = InteractionState::iter(); Story::container(cx) diff --git a/crates/ui2/src/elements/details.rs b/crates/ui2/src/elements/details.rs index ea05436401..5f0676f9f4 100644 --- a/crates/ui2/src/elements/details.rs +++ b/crates/ui2/src/elements/details.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::{prelude::*, v_stack, ButtonGroup}; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Details { state_type: PhantomData, text: &'static str, @@ -30,7 +30,7 @@ impl Details { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); v_stack() @@ -54,7 +54,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct DetailsStory { state_type: PhantomData, } @@ -66,7 +66,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Details>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/icon.rs b/crates/ui2/src/elements/icon.rs index 2a0f6b3a0b..18d6050dd1 100644 --- a/crates/ui2/src/elements/icon.rs +++ b/crates/ui2/src/elements/icon.rs @@ -148,7 +148,7 @@ impl Icon { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct IconElement { state_type: PhantomData, icon: Icon, @@ -176,7 +176,7 @@ impl IconElement { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let fill = self.color.color(cx); let svg_size = match self.size { IconSize::Small => ui_size(cx, 12. / 14.), @@ -202,7 +202,7 @@ mod stories { use super::*; - #[derive(Element, Default)] + #[derive(IntoAnyElement)] pub struct IconStory { state_type: PhantomData, } @@ -214,7 +214,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let icons = Icon::iter(); Story::container(cx) diff --git a/crates/ui2/src/elements/input.rs b/crates/ui2/src/elements/input.rs index 142acc8870..6a70c9cf79 100644 --- a/crates/ui2/src/elements/input.rs +++ b/crates/ui2/src/elements/input.rs @@ -11,7 +11,7 @@ pub enum InputVariant { Filled, } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Input { state_type: PhantomData, placeholder: SharedString, @@ -60,7 +60,7 @@ impl Input { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let (input_bg, input_hover_bg, input_active_bg) = match self.variant { @@ -120,7 +120,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct InputStory { state_type: PhantomData, } @@ -132,7 +132,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Input>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/label.rs b/crates/ui2/src/elements/label.rs index f8d4a8d115..2d522a27b1 100644 --- a/crates/ui2/src/elements/label.rs +++ b/crates/ui2/src/elements/label.rs @@ -48,7 +48,7 @@ pub enum LineHeightStyle { UILabel, } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct Label { state_type: PhantomData, label: SharedString, @@ -83,7 +83,7 @@ impl Label { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { div() .when(self.strikethrough, |this| { this.relative().child( @@ -105,7 +105,7 @@ impl Label { } } -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct HighlightedLabel { state_type: PhantomData, label: SharedString, @@ -135,7 +135,7 @@ impl HighlightedLabel { self } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); let highlight_color = theme.text_accent; @@ -211,7 +211,7 @@ mod stories { use super::*; - #[derive(Element)] + #[derive(IntoAnyElement)] pub struct LabelStory { state_type: PhantomData, } @@ -223,7 +223,7 @@ mod stories { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { Story::container(cx) .child(Story::title_for::<_, Label>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/tool_divider.rs b/crates/ui2/src/elements/tool_divider.rs index f73c8953ee..b388894d1a 100644 --- a/crates/ui2/src/elements/tool_divider.rs +++ b/crates/ui2/src/elements/tool_divider.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::prelude::*; -#[derive(Element)] +#[derive(IntoAnyElement)] pub struct ToolDivider { state_type: PhantomData, } @@ -14,7 +14,7 @@ impl ToolDivider { } } - fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { let theme = theme(cx); div().w_px().h_3().bg(theme.border) From 0285284ae1fe8c3878eb56aaaeecc4ad96804e43 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Oct 2023 12:46:52 +0200 Subject: [PATCH 13/24] Rename IntoAnyElement trait to Component --- crates/gpui2/src/element.rs | 32 +++++----- crates/gpui2/src/elements/div.rs | 10 +-- crates/gpui2/src/elements/img.rs | 8 +-- crates/gpui2/src/elements/svg.rs | 8 +-- crates/gpui2/src/elements/text.rs | 26 ++++---- crates/gpui2/src/interactive.rs | 12 ++-- crates/gpui2/src/view.rs | 22 +++---- ...nto_any_element.rs => derive_component.rs} | 10 +-- crates/gpui2_macros/src/gpui2_macros.rs | 8 +-- crates/storybook2/src/components.rs | 2 +- crates/storybook2/src/stories/kitchen_sink.rs | 2 +- crates/storybook2/src/stories/scroll.rs | 5 +- crates/storybook2/src/stories/z_index.rs | 8 +-- crates/storybook2/src/story_selector.rs | 62 +++++++++---------- crates/storybook2/src/storybook2.rs | 2 +- crates/ui2/src/components/assistant_panel.rs | 10 +-- crates/ui2/src/components/breadcrumb.rs | 8 +-- crates/ui2/src/components/buffer.rs | 12 ++-- crates/ui2/src/components/buffer_search.rs | 2 +- crates/ui2/src/components/chat_panel.rs | 12 ++-- crates/ui2/src/components/collab_panel.rs | 8 +-- crates/ui2/src/components/command_palette.rs | 8 +-- crates/ui2/src/components/context_menu.rs | 8 +-- crates/ui2/src/components/copilot.rs | 8 +-- crates/ui2/src/components/editor_pane.rs | 2 +- crates/ui2/src/components/facepile.rs | 8 +-- crates/ui2/src/components/icon_button.rs | 4 +- crates/ui2/src/components/keybinding.rs | 12 ++-- .../ui2/src/components/language_selector.rs | 8 +-- crates/ui2/src/components/list.rs | 30 ++++----- crates/ui2/src/components/modal.rs | 4 +- crates/ui2/src/components/multi_buffer.rs | 8 +-- .../ui2/src/components/notification_toast.rs | 4 +- .../ui2/src/components/notifications_panel.rs | 8 +-- crates/ui2/src/components/palette.rs | 12 ++-- crates/ui2/src/components/panel.rs | 8 +-- crates/ui2/src/components/panes.rs | 8 +-- crates/ui2/src/components/player_stack.rs | 4 +- crates/ui2/src/components/project_panel.rs | 8 +-- crates/ui2/src/components/recent_projects.rs | 8 +-- crates/ui2/src/components/status_bar.rs | 10 +-- crates/ui2/src/components/tab.rs | 8 +-- crates/ui2/src/components/tab_bar.rs | 8 +-- crates/ui2/src/components/terminal.rs | 8 +-- crates/ui2/src/components/theme_selector.rs | 8 +-- crates/ui2/src/components/title_bar.rs | 4 +- crates/ui2/src/components/toast.rs | 8 +-- crates/ui2/src/components/toolbar.rs | 24 +++---- crates/ui2/src/components/traffic_lights.rs | 12 ++-- crates/ui2/src/components/workspace.rs | 2 +- crates/ui2/src/elements/avatar.rs | 8 +-- crates/ui2/src/elements/button.rs | 12 ++-- crates/ui2/src/elements/details.rs | 8 +-- crates/ui2/src/elements/icon.rs | 8 +-- crates/ui2/src/elements/input.rs | 8 +-- crates/ui2/src/elements/label.rs | 12 ++-- crates/ui2/src/elements/tool_divider.rs | 4 +- crates/ui2/src/prelude.rs | 2 +- crates/ui2/src/story.rs | 8 +-- crates/ui2/src/theme.rs | 6 +- 60 files changed, 297 insertions(+), 300 deletions(-) rename crates/gpui2_macros/src/{derive_into_any_element.rs => derive_component.rs} (84%) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index 39b7898d16..762c887342 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -46,20 +46,20 @@ pub struct GlobalElementId(SmallVec<[ElementId; 32]>); pub trait ParentElement { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; - fn child(mut self, child: impl IntoAnyElement) -> Self + fn child(mut self, child: impl Component) -> Self where Self: Sized, { - self.children_mut().push(child.into_any()); + self.children_mut().push(child.render()); self } - fn children(mut self, iter: impl IntoIterator>) -> Self + fn children(mut self, iter: impl IntoIterator>) -> Self where Self: Sized, { self.children_mut() - .extend(iter.into_iter().map(|item| item.into_any())); + .extend(iter.into_iter().map(|item| item.render())); self } } @@ -207,8 +207,8 @@ impl AnyElement { } } -pub trait IntoAnyElement { - fn into_any(self) -> AnyElement; +pub trait Component { + fn render(self) -> AnyElement; fn when(mut self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self where @@ -221,8 +221,8 @@ pub trait IntoAnyElement { } } -impl IntoAnyElement for AnyElement { - fn into_any(self) -> AnyElement { +impl Component for AnyElement { + fn render(self) -> AnyElement { self } } @@ -230,7 +230,7 @@ impl IntoAnyElement for AnyElement { impl Element for Option where V: 'static, - E: 'static + IntoAnyElement + Send + Sync, + E: 'static + Component + Send + Sync, F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + Sync + 'static, { type ElementState = AnyElement; @@ -246,7 +246,7 @@ where cx: &mut ViewContext, ) -> Self::ElementState { let render = self.take().unwrap(); - (render)(view_state, cx).into_any() + (render)(view_state, cx).render() } fn layout( @@ -269,24 +269,24 @@ where } } -impl IntoAnyElement for Option +impl Component for Option where V: 'static, - E: 'static + IntoAnyElement + Send + Sync, + E: 'static + Component + Send + Sync, F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + Sync + 'static, { - fn into_any(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } -impl IntoAnyElement for F +impl Component for F where V: 'static, - E: 'static + IntoAnyElement + Send + Sync, + E: 'static + Component + Send + Sync, F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + Sync + 'static, { - fn into_any(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(Some(self)) } } diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index fbef75ab1c..6fe10d94a3 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -1,7 +1,7 @@ use crate::{ - point, AnyElement, BorrowWindow, Bounds, Element, ElementFocus, ElementId, ElementInteraction, - FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable, GlobalElementId, - GroupBounds, InteractiveElementState, IntoAnyElement, LayoutId, Overflow, ParentElement, + point, AnyElement, BorrowWindow, Bounds, Component, Element, ElementFocus, ElementId, + ElementInteraction, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable, + GlobalElementId, GroupBounds, InteractiveElementState, LayoutId, Overflow, ParentElement, Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction, StatelessInteractive, Style, StyleRefinement, Styled, ViewContext, }; @@ -303,13 +303,13 @@ where } } -impl IntoAnyElement for Div +impl Component for Div where // V: Any + Send + Sync, I: ElementInteraction, F: ElementFocus, { - fn into_any(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } diff --git a/crates/gpui2/src/elements/img.rs b/crates/gpui2/src/elements/img.rs index d64536a7ed..747e573ea5 100644 --- a/crates/gpui2/src/elements/img.rs +++ b/crates/gpui2/src/elements/img.rs @@ -1,6 +1,6 @@ use crate::{ - div, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementFocus, ElementId, - ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, IntoAnyElement, + div, AnyElement, BorrowWindow, Bounds, Component, Div, DivState, Element, ElementFocus, + ElementId, ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, LayoutId, Pixels, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction, StatelessInteractive, StyleRefinement, Styled, ViewContext, }; @@ -55,12 +55,12 @@ where } } -impl IntoAnyElement for Img +impl Component for Img where I: ElementInteraction, F: ElementFocus, { - fn into_any(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } diff --git a/crates/gpui2/src/elements/svg.rs b/crates/gpui2/src/elements/svg.rs index 409094d740..7db4c5cf6d 100644 --- a/crates/gpui2/src/elements/svg.rs +++ b/crates/gpui2/src/elements/svg.rs @@ -1,6 +1,6 @@ use crate::{ - div, AnyElement, Bounds, Div, DivState, Element, ElementFocus, ElementId, ElementInteraction, - FocusDisabled, FocusEnabled, FocusListeners, Focusable, IntoAnyElement, LayoutId, Pixels, + div, AnyElement, Bounds, Component, Div, DivState, Element, ElementFocus, ElementId, + ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, LayoutId, Pixels, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction, StatelessInteractive, StyleRefinement, Styled, ViewContext, }; @@ -45,12 +45,12 @@ where } } -impl IntoAnyElement for Svg +impl Component for Svg where I: ElementInteraction, F: ElementFocus, { - fn into_any(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } diff --git a/crates/gpui2/src/elements/text.rs b/crates/gpui2/src/elements/text.rs index e054da87a6..3aff568c4c 100644 --- a/crates/gpui2/src/elements/text.rs +++ b/crates/gpui2/src/elements/text.rs @@ -1,41 +1,41 @@ use crate::{ - AnyElement, BorrowWindow, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, - SharedString, Size, ViewContext, + AnyElement, BorrowWindow, Bounds, Component, Element, LayoutId, Line, Pixels, SharedString, + Size, ViewContext, }; use parking_lot::Mutex; use smallvec::SmallVec; use std::{marker::PhantomData, sync::Arc}; use util::ResultExt; -impl IntoAnyElement for SharedString { - fn into_any(self) -> AnyElement { +impl Component for SharedString { + fn render(self) -> AnyElement { Text { text: self, state_type: PhantomData, } - .into_any() + .render() } } -impl IntoAnyElement for &'static str { - fn into_any(self) -> AnyElement { +impl Component for &'static str { + fn render(self) -> AnyElement { Text { text: self.into(), state_type: PhantomData, } - .into_any() + .render() } } // TODO: Figure out how to pass `String` to `child` without this. // This impl doesn't exist in the `gpui2` crate. -impl IntoAnyElement for String { - fn into_any(self) -> AnyElement { +impl Component for String { + fn render(self) -> AnyElement { Text { text: self.into(), state_type: PhantomData, } - .into_any() + .render() } } @@ -47,8 +47,8 @@ pub struct Text { unsafe impl Send for Text {} unsafe impl Sync for Text {} -impl IntoAnyElement for Text { - fn into_any(self) -> AnyElement { +impl Component for Text { + fn render(self) -> AnyElement { AnyElement::new(self) } } diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index f51516dbe5..9ec6c38dfe 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -1,7 +1,7 @@ use crate::{ - point, px, view, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, DispatchContext, - DispatchPhase, Element, ElementId, FocusHandle, IntoAnyElement, KeyMatch, Keystroke, Modifiers, - Overflow, Pixels, Point, SharedString, Size, Style, StyleRefinement, ViewContext, + point, px, view, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, Component, + DispatchContext, DispatchPhase, Element, ElementId, FocusHandle, KeyMatch, Keystroke, + Modifiers, Overflow, Pixels, Point, SharedString, Size, Style, StyleRefinement, ViewContext, }; use collections::HashMap; use derive_more::{Deref, DerefMut}; @@ -327,7 +327,7 @@ pub trait StatefulInteractive: StatelessInteractive { S: Any + Send + Sync, R: Fn(&mut V, &mut ViewContext) -> E, R: 'static + Send + Sync, - E: IntoAnyElement, + E: Component, { debug_assert!( self.stateful_interaction().drag_listener.is_none(), @@ -871,7 +871,7 @@ pub struct Drag where R: Fn(&mut V, &mut ViewContext) -> E, V: 'static, - E: IntoAnyElement, + E: Component, { pub state: S, pub render_drag_handle: R, @@ -882,7 +882,7 @@ impl Drag where R: Fn(&mut V, &mut ViewContext) -> E, V: 'static, - E: IntoAnyElement, + E: Component, { pub fn new(state: S, render_drag_handle: R) -> Self { Drag { diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index b1b287c4ab..a27faed07d 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -1,7 +1,7 @@ use parking_lot::Mutex; use crate::{ - AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, EntityId, Handle, IntoAnyElement, + AnyBox, AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, EntityId, Handle, LayoutId, Pixels, ViewContext, WindowContext, }; use std::{marker::PhantomData, sync::Arc}; @@ -33,16 +33,16 @@ pub fn view( render: impl Fn(&mut V, &mut ViewContext) -> E + Send + Sync + 'static, ) -> View where - E: IntoAnyElement, + E: Component, { View { state, - render: Arc::new(move |state, cx| render(state, cx).into_any()), + render: Arc::new(move |state, cx| render(state, cx).render()), } } -impl IntoAnyElement for View { - fn into_any(self) -> AnyElement { +impl Component for View { + fn render(self) -> AnyElement { AnyElement::new(EraseViewState { view: self, parent_view_state_type: PhantomData, @@ -98,8 +98,8 @@ struct EraseViewState { unsafe impl Send for EraseViewState {} unsafe impl Sync for EraseViewState {} -impl IntoAnyElement for EraseViewState { - fn into_any(self) -> AnyElement { +impl Component for EraseViewState { + fn render(self) -> AnyElement { AnyElement::new(self) } } @@ -185,8 +185,8 @@ pub struct AnyView { view: Arc>, } -impl IntoAnyElement for AnyView { - fn into_any(self) -> AnyElement { +impl Component for AnyView { + fn render(self) -> AnyElement { AnyElement::new(EraseAnyViewState { view: self, parent_view_state_type: PhantomData, @@ -238,8 +238,8 @@ struct EraseAnyViewState { unsafe impl Send for EraseAnyViewState {} unsafe impl Sync for EraseAnyViewState {} -impl IntoAnyElement for EraseAnyViewState { - fn into_any(self) -> AnyElement { +impl Component for EraseAnyViewState { + fn render(self) -> AnyElement { AnyElement::new(self) } } diff --git a/crates/gpui2_macros/src/derive_into_any_element.rs b/crates/gpui2_macros/src/derive_component.rs similarity index 84% rename from crates/gpui2_macros/src/derive_into_any_element.rs rename to crates/gpui2_macros/src/derive_component.rs index 9f339f1b44..45f4b44c85 100644 --- a/crates/gpui2_macros/src/derive_into_any_element.rs +++ b/crates/gpui2_macros/src/derive_component.rs @@ -2,7 +2,7 @@ use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, DeriveInput}; -pub fn derive_into_any_element(input: TokenStream) -> TokenStream { +pub fn derive_component(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident; let generics = &ast.generics; @@ -11,7 +11,7 @@ pub fn derive_into_any_element(input: TokenStream) -> TokenStream { let specified_view_type = ast .attrs .iter() - .find(|attr| attr.path.is_ident("element")) + .find(|attr| attr.path.is_ident("component")) .and_then(|attr| { if let Ok(syn::Meta::List(meta_list)) = attr.parse_meta() { meta_list.nested.iter().find_map(|nested| { @@ -42,10 +42,10 @@ pub fn derive_into_any_element(input: TokenStream) -> TokenStream { }); let expanded = quote! { - impl #impl_generics gpui2::IntoAnyElement<#view_type> for #name #ty_generics #where_clause { - fn into_any(self) -> gpui2::AnyElement<#view_type> { + impl #impl_generics gpui2::Component<#view_type> for #name #ty_generics #where_clause { + fn render(self) -> gpui2::AnyElement<#view_type> { (move |view_state: &mut #view_type, cx: &mut gpui2::ViewContext<'_, '_, #view_type>| self.render(view_state, cx)) - .into_any() + .render() } } }; diff --git a/crates/gpui2_macros/src/gpui2_macros.rs b/crates/gpui2_macros/src/gpui2_macros.rs index 3635320d55..2e0c0547f7 100644 --- a/crates/gpui2_macros/src/gpui2_macros.rs +++ b/crates/gpui2_macros/src/gpui2_macros.rs @@ -1,6 +1,6 @@ use proc_macro::TokenStream; -mod derive_into_any_element; +mod derive_component; mod style_helpers; mod test; @@ -9,9 +9,9 @@ pub fn style_helpers(args: TokenStream) -> TokenStream { style_helpers::style_helpers(args) } -#[proc_macro_derive(IntoAnyElement, attributes(element))] -pub fn derive_into_any_element(input: TokenStream) -> TokenStream { - derive_into_any_element::derive_into_any_element(input) +#[proc_macro_derive(Component, attributes(component))] +pub fn derive_component(input: TokenStream) -> TokenStream { + derive_component::derive_component(input) } #[proc_macro_attribute] diff --git a/crates/storybook2/src/components.rs b/crates/storybook2/src/components.rs index 5eaa894302..a3dca51adc 100644 --- a/crates/storybook2/src/components.rs +++ b/crates/storybook2/src/components.rs @@ -14,7 +14,7 @@ impl Default for ButtonHandlers { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Button { handlers: ButtonHandlers, label: Option>, diff --git a/crates/storybook2/src/stories/kitchen_sink.rs b/crates/storybook2/src/stories/kitchen_sink.rs index fbb4f5099c..ec89238ac4 100644 --- a/crates/storybook2/src/stories/kitchen_sink.rs +++ b/crates/storybook2/src/stories/kitchen_sink.rs @@ -16,7 +16,7 @@ impl KitchenSinkStory { view(cx.entity(|cx| Self::new()), Self::render) } - fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(&mut self, cx: &mut ViewContext) -> impl Component { let element_stories = ElementStory::iter() .map(|selector| selector.story(cx)) .collect::>(); diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs index 86a8ca41c8..a1e3c6700e 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -1,7 +1,6 @@ use crate::themes::rose_pine; use gpui2::{ - div, px, view, Context, IntoAnyElement, ParentElement, SharedString, Styled, View, - WindowContext, + div, px, view, Component, Context, ParentElement, SharedString, Styled, View, WindowContext, }; pub struct ScrollStory { @@ -16,7 +15,7 @@ impl ScrollStory { } } -fn checkerboard(depth: usize) -> impl IntoAnyElement +fn checkerboard(depth: usize) -> impl Component where S: 'static + Send + Sync, { diff --git a/crates/storybook2/src/stories/z_index.rs b/crates/storybook2/src/stories/z_index.rs index 270bd08640..d68b4916c2 100644 --- a/crates/storybook2/src/stories/z_index.rs +++ b/crates/storybook2/src/stories/z_index.rs @@ -7,7 +7,7 @@ use crate::story::Story; /// A reimplementation of the MDN `z-index` example, found here: /// [https://developer.mozilla.org/en-US/docs/Web/CSS/z-index](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index). -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ZIndexStory { state_type: PhantomData, } @@ -19,7 +19,7 @@ impl ZIndexStory { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title(cx, "z-index")) .child( @@ -88,7 +88,7 @@ trait Styles: Styled + Sized { impl Styles for Div {} -#[derive(IntoAnyElement)] +#[derive(Component)] struct ZIndexExample { view_type: PhantomData, z_index: u32, @@ -102,7 +102,7 @@ impl ZIndexExample { } } - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { div() .relative() .size_full() diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index 8cd3f9e329..5f60ad14ea 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -28,29 +28,29 @@ impl ElementStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { Self::Avatar => { - view(cx.entity(|cx| ()), |_, _| ui::AvatarStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::AvatarStory::new().render()).into_any() } Self::Button => { - view(cx.entity(|cx| ()), |_, _| ui::ButtonStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::ButtonStory::new().render()).into_any() } Self::Details => view(cx.entity(|cx| ()), |_, _| { - ui::DetailsStory::new().into_any() + ui::DetailsStory::new().render() }) .into_any(), Self::Focus => FocusStory::view(cx).into_any(), Self::Icon => { - view(cx.entity(|cx| ()), |_, _| ui::IconStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::IconStory::new().render()).into_any() } Self::Input => { - view(cx.entity(|cx| ()), |_, _| ui::InputStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::InputStory::new().render()).into_any() } Self::Label => { - view(cx.entity(|cx| ()), |_, _| ui::LabelStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::LabelStory::new().render()).into_any() } Self::Scroll => ScrollStory::view(cx).into_any(), Self::Text => TextStory::view(cx).into_any(), Self::ZIndex => { - view(cx.entity(|cx| ()), |_, _| ZIndexStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ZIndexStory::new().render()).into_any() } } } @@ -91,93 +91,93 @@ impl ComponentStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { Self::AssistantPanel => view(cx.entity(|cx| ()), |_, _| { - ui::AssistantPanelStory::new().into_any() + ui::AssistantPanelStory::new().render() }) .into_any(), Self::Buffer => { - view(cx.entity(|cx| ()), |_, _| ui::BufferStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::BufferStory::new().render()).into_any() } Self::Breadcrumb => view(cx.entity(|cx| ()), |_, _| { - ui::BreadcrumbStory::new().into_any() + ui::BreadcrumbStory::new().render() }) .into_any(), Self::ChatPanel => view(cx.entity(|cx| ()), |_, _| { - ui::ChatPanelStory::new().into_any() + ui::ChatPanelStory::new().render() }) .into_any(), Self::CollabPanel => view(cx.entity(|cx| ()), |_, _| { - ui::CollabPanelStory::new().into_any() + ui::CollabPanelStory::new().render() }) .into_any(), Self::CommandPalette => view(cx.entity(|cx| ()), |_, _| { - ui::CommandPaletteStory::new().into_any() + ui::CommandPaletteStory::new().render() }) .into_any(), Self::ContextMenu => view(cx.entity(|cx| ()), |_, _| { - ui::ContextMenuStory::new().into_any() + ui::ContextMenuStory::new().render() }) .into_any(), Self::Facepile => view(cx.entity(|cx| ()), |_, _| { - ui::FacepileStory::new().into_any() + ui::FacepileStory::new().render() }) .into_any(), Self::Keybinding => view(cx.entity(|cx| ()), |_, _| { - ui::KeybindingStory::new().into_any() + ui::KeybindingStory::new().render() }) .into_any(), Self::LanguageSelector => view(cx.entity(|cx| ()), |_, _| { - ui::LanguageSelectorStory::new().into_any() + ui::LanguageSelectorStory::new().render() }) .into_any(), Self::MultiBuffer => view(cx.entity(|cx| ()), |_, _| { - ui::MultiBufferStory::new().into_any() + ui::MultiBufferStory::new().render() }) .into_any(), Self::NotificationsPanel => view(cx.entity(|cx| ()), |_, _| { - ui::NotificationsPanelStory::new().into_any() + ui::NotificationsPanelStory::new().render() }) .into_any(), Self::Palette => view(cx.entity(|cx| ()), |_, _| { - ui::PaletteStory::new().into_any() + ui::PaletteStory::new().render() }) .into_any(), Self::Panel => { - view(cx.entity(|cx| ()), |_, _| ui::PanelStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::PanelStory::new().render()).into_any() } Self::ProjectPanel => view(cx.entity(|cx| ()), |_, _| { - ui::ProjectPanelStory::new().into_any() + ui::ProjectPanelStory::new().render() }) .into_any(), Self::RecentProjects => view(cx.entity(|cx| ()), |_, _| { - ui::RecentProjectsStory::new().into_any() + ui::RecentProjectsStory::new().render() }) .into_any(), - Self::Tab => view(cx.entity(|cx| ()), |_, _| ui::TabStory::new().into_any()).into_any(), + Self::Tab => view(cx.entity(|cx| ()), |_, _| ui::TabStory::new().render()).into_any(), Self::TabBar => { - view(cx.entity(|cx| ()), |_, _| ui::TabBarStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::TabBarStory::new().render()).into_any() } Self::Terminal => view(cx.entity(|cx| ()), |_, _| { - ui::TerminalStory::new().into_any() + ui::TerminalStory::new().render() }) .into_any(), Self::ThemeSelector => view(cx.entity(|cx| ()), |_, _| { - ui::ThemeSelectorStory::new().into_any() + ui::ThemeSelectorStory::new().render() }) .into_any(), Self::TitleBar => ui::TitleBarStory::view(cx).into_any(), Self::Toast => { - view(cx.entity(|cx| ()), |_, _| ui::ToastStory::new().into_any()).into_any() + view(cx.entity(|cx| ()), |_, _| ui::ToastStory::new().render()).into_any() } Self::Toolbar => view(cx.entity(|cx| ()), |_, _| { - ui::ToolbarStory::new().into_any() + ui::ToolbarStory::new().render() }) .into_any(), Self::TrafficLights => view(cx.entity(|cx| ()), |_, _| { - ui::TrafficLightsStory::new().into_any() + ui::TrafficLightsStory::new().render() }) .into_any(), Self::Copilot => view(cx.entity(|cx| ()), |_, _| { - ui::CopilotModalStory::new().into_any() + ui::CopilotModalStory::new().render() }) .into_any(), Self::Workspace => ui::WorkspaceStory::view(cx).into_any(), diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index 4db1fd434b..29ff5eaa98 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -107,7 +107,7 @@ impl StoryWrapper { Self { story, theme } } - fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(&mut self, cx: &mut ViewContext) -> impl Component { themed(self.theme.clone(), cx, |cx| { div() .flex() diff --git a/crates/ui2/src/components/assistant_panel.rs b/crates/ui2/src/components/assistant_panel.rs index fa5ac38dc1..c07723cedb 100644 --- a/crates/ui2/src/components/assistant_panel.rs +++ b/crates/ui2/src/components/assistant_panel.rs @@ -5,7 +5,7 @@ use gpui2::{rems, AbsoluteLength}; use crate::prelude::*; use crate::{Icon, IconButton, Label, Panel, PanelSide}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct AssistantPanel { id: ElementId, state_type: PhantomData, @@ -26,7 +26,7 @@ impl AssistantPanel { self } - fn render(self, view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, view: &mut S, cx: &mut ViewContext) -> impl Component { Panel::new(self.id.clone(), cx) .children(vec![div() .flex() @@ -69,7 +69,7 @@ impl AssistantPanel { .overflow_y_scroll() .child(Label::new("Is this thing on?")), ) - .into_any()]) + .render()]) .side(self.current_side) .width(AbsoluteLength::Rems(rems(32.))) } @@ -84,7 +84,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct AssistantPanelStory { state_type: PhantomData, } @@ -96,7 +96,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, AssistantPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/breadcrumb.rs b/crates/ui2/src/components/breadcrumb.rs index 00a471e7cc..289c071021 100644 --- a/crates/ui2/src/components/breadcrumb.rs +++ b/crates/ui2/src/components/breadcrumb.rs @@ -9,7 +9,7 @@ use crate::{h_stack, HighlightedText}; #[derive(Clone)] pub struct Symbol(pub Vec); -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Breadcrumb { state_type: PhantomData, path: PathBuf, @@ -31,7 +31,7 @@ impl Breadcrumb { div().child(" › ").text_color(theme.text_muted) } - fn render(self, view_state: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, view_state: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let symbols_len = self.symbols.len(); @@ -86,7 +86,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct BreadcrumbStory { state_type: PhantomData, } @@ -98,7 +98,7 @@ mod stories { } } - fn render(self, view_state: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, view_state: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer.rs b/crates/ui2/src/components/buffer.rs index 662ccd5736..ffef5c4039 100644 --- a/crates/ui2/src/components/buffer.rs +++ b/crates/ui2/src/components/buffer.rs @@ -109,7 +109,7 @@ impl BufferRow { } } -#[derive(IntoAnyElement, Clone)] +#[derive(Component, Clone)] pub struct Buffer { id: ElementId, state_type: PhantomData, @@ -158,7 +158,7 @@ impl Buffer { self } - fn render_row(row: BufferRow, cx: &WindowContext) -> impl IntoAnyElement { + fn render_row(row: BufferRow, cx: &WindowContext) -> impl Component { let theme = theme(cx); let line_background = if row.current { @@ -208,7 +208,7 @@ impl Buffer { })) } - fn render_rows(&self, cx: &WindowContext) -> Vec> { + fn render_rows(&self, cx: &WindowContext) -> Vec> { match &self.rows { Some(rows) => rows .rows @@ -219,7 +219,7 @@ impl Buffer { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let rows = self.render_rows(cx); @@ -246,7 +246,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct BufferStory { state_type: PhantomData, } @@ -258,7 +258,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer_search.rs b/crates/ui2/src/components/buffer_search.rs index e3e92aa073..b5e74a4810 100644 --- a/crates/ui2/src/components/buffer_search.rs +++ b/crates/ui2/src/components/buffer_search.rs @@ -25,7 +25,7 @@ impl BufferSearch { view(cx.entity(|cx| Self::new()), Self::render) } - fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(&mut self, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); h_stack().bg(theme.toolbar).p_2().child( diff --git a/crates/ui2/src/components/chat_panel.rs b/crates/ui2/src/components/chat_panel.rs index db0f573485..2800207b34 100644 --- a/crates/ui2/src/components/chat_panel.rs +++ b/crates/ui2/src/components/chat_panel.rs @@ -5,7 +5,7 @@ use chrono::NaiveDateTime; use crate::prelude::*; use crate::{Icon, IconButton, Input, Label, LabelColor}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ChatPanel { element_id: ElementId, messages: Vec>, @@ -24,7 +24,7 @@ impl ChatPanel { self } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .id(self.element_id.clone()) .flex() @@ -70,7 +70,7 @@ impl ChatPanel { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ChatMessage { state_type: PhantomData, author: String, @@ -88,7 +88,7 @@ impl ChatMessage { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .flex() .flex_col() @@ -117,7 +117,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct ChatPanelStory { state_type: PhantomData, } @@ -129,7 +129,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, ChatPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/collab_panel.rs b/crates/ui2/src/components/collab_panel.rs index 050b7c2b85..8f30b33da0 100644 --- a/crates/ui2/src/components/collab_panel.rs +++ b/crates/ui2/src/components/collab_panel.rs @@ -5,7 +5,7 @@ use crate::{ }; use std::marker::PhantomData; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct CollabPanel { id: ElementId, state_type: PhantomData, @@ -19,7 +19,7 @@ impl CollabPanel { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); v_stack() @@ -98,7 +98,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct CollabPanelStory { state_type: PhantomData, } @@ -110,7 +110,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, CollabPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/command_palette.rs b/crates/ui2/src/components/command_palette.rs index f79038b172..d00b9b7743 100644 --- a/crates/ui2/src/components/command_palette.rs +++ b/crates/ui2/src/components/command_palette.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{example_editor_actions, OrderMethod, Palette}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct CommandPalette { id: ElementId, state_type: PhantomData, @@ -17,7 +17,7 @@ impl CommandPalette { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().id(self.id.clone()).child( Palette::new("palette") .items(example_editor_actions()) @@ -37,7 +37,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct CommandPaletteStory { state_type: PhantomData, } @@ -49,7 +49,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, CommandPalette>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 5463cb29e7..b52051daa3 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -31,7 +31,7 @@ impl ContextMenuItem { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ContextMenu { items: Vec>, } @@ -42,7 +42,7 @@ impl ContextMenu { items: items.into_iter().collect(), } } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); v_stack() @@ -73,7 +73,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct ContextMenuStory { state_type: PhantomData, } @@ -85,7 +85,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, ContextMenu>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/copilot.rs b/crates/ui2/src/components/copilot.rs index ca82ea5a0a..9e5454ee8a 100644 --- a/crates/ui2/src/components/copilot.rs +++ b/crates/ui2/src/components/copilot.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::{prelude::*, Button, Label, LabelColor, Modal}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct CopilotModal { id: ElementId, state_type: PhantomData, @@ -16,7 +16,7 @@ impl CopilotModal { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().id(self.id.clone()).child( Modal::new("some-id") .title("Connect Copilot to Zed") @@ -35,7 +35,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct CopilotModalStory { state_type: PhantomData, } @@ -47,7 +47,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, CopilotModal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/editor_pane.rs b/crates/ui2/src/components/editor_pane.rs index 3fc41d7db6..fb26dad791 100644 --- a/crates/ui2/src/components/editor_pane.rs +++ b/crates/ui2/src/components/editor_pane.rs @@ -49,7 +49,7 @@ impl EditorPane { ) } - fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(&mut self, cx: &mut ViewContext) -> impl Component { v_stack() .w_full() .h_full() diff --git a/crates/ui2/src/components/facepile.rs b/crates/ui2/src/components/facepile.rs index c87de6a2a2..565396e733 100644 --- a/crates/ui2/src/components/facepile.rs +++ b/crates/ui2/src/components/facepile.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{Avatar, Player}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Facepile { state_type: PhantomData, players: Vec, @@ -17,7 +17,7 @@ impl Facepile { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let player_count = self.players.len(); let player_list = self.players.iter().enumerate().map(|(ix, player)| { let isnt_last = ix < player_count - 1; @@ -39,7 +39,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct FacepileStory { state_type: PhantomData, } @@ -51,7 +51,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let players = static_players(); Story::container(cx) diff --git a/crates/ui2/src/components/icon_button.rs b/crates/ui2/src/components/icon_button.rs index 0801c5ac23..fe41de15a0 100644 --- a/crates/ui2/src/components/icon_button.rs +++ b/crates/ui2/src/components/icon_button.rs @@ -16,7 +16,7 @@ impl Default for IconButtonHandlers { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct IconButton { state_type: PhantomData, id: ElementId, @@ -68,7 +68,7 @@ impl IconButton { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let icon_color = match (self.state, self.color) { diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index 7a240aa39c..d77798ad6c 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -5,7 +5,7 @@ use strum::{EnumIter, IntoEnumIterator}; use crate::prelude::*; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Keybinding { state_type: PhantomData, @@ -34,7 +34,7 @@ impl Keybinding { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .flex() .gap_2() @@ -54,7 +54,7 @@ impl Keybinding { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Key { state_type: PhantomData, key: SharedString, @@ -68,7 +68,7 @@ impl Key { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); div() @@ -173,7 +173,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct KeybindingStory { state_type: PhantomData, } @@ -185,7 +185,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let all_modifier_permutations = ModifierKey::iter().permutations(2); Story::container(cx) diff --git a/crates/ui2/src/components/language_selector.rs b/crates/ui2/src/components/language_selector.rs index 5dd571ec42..ebb8f152f8 100644 --- a/crates/ui2/src/components/language_selector.rs +++ b/crates/ui2/src/components/language_selector.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{OrderMethod, Palette, PaletteItem}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct LanguageSelector { id: ElementId, state_type: PhantomData, @@ -17,7 +17,7 @@ impl LanguageSelector { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().id(self.id.clone()).child( Palette::new("palette") .items(vec![ @@ -48,7 +48,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct LanguageSelectorStory { state_type: PhantomData, } @@ -60,7 +60,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, LanguageSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index 00684a7eb9..b1b3f506ea 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -17,7 +17,7 @@ pub enum ListItemVariant { Inset, } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ListHeader { state_type: PhantomData, label: SharedString, @@ -92,7 +92,7 @@ impl ListHeader { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let is_toggleable = self.toggleable != Toggleable::NotToggleable; @@ -134,7 +134,7 @@ impl ListHeader { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ListSubHeader { state_type: PhantomData, label: SharedString, @@ -157,7 +157,7 @@ impl ListSubHeader { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { h_stack().flex_1().w_full().relative().py_1().child( div() .h_6() @@ -197,7 +197,7 @@ pub enum ListEntrySize { Medium, } -#[derive(IntoAnyElement)] +#[derive(Component)] pub enum ListItem { Entry(ListEntry), Details(ListDetailsEntry), @@ -230,7 +230,7 @@ impl From> for ListItem { } impl ListItem { - fn render(self, view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, view: &mut S, cx: &mut ViewContext) -> impl Component { match self { ListItem::Entry(entry) => div().child(entry.render(view, cx)), ListItem::Separator(separator) => div().child(separator.render(view, cx)), @@ -252,7 +252,7 @@ impl ListItem { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ListEntry { disclosure_control_style: DisclosureControlVisibility, indent_level: u32, @@ -344,7 +344,7 @@ impl ListEntry { } } - fn disclosure_control(&mut self, cx: &mut ViewContext) -> Option> { + fn disclosure_control(&mut self, cx: &mut ViewContext) -> Option> { let disclosure_control_icon = if let Some(ToggleState::Toggled) = self.toggle { IconElement::new(Icon::ChevronDown) } else { @@ -364,7 +364,7 @@ impl ListEntry { } } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let settings = user_settings(cx); let theme = theme(cx); @@ -430,7 +430,7 @@ impl Default for ListDetailsEntryHandlers { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ListDetailsEntry { label: SharedString, meta: Option, @@ -474,7 +474,7 @@ impl ListDetailsEntry { self } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let settings = user_settings(cx); @@ -519,7 +519,7 @@ impl ListDetailsEntry { } } -#[derive(Clone, IntoAnyElement)] +#[derive(Clone, Component)] pub struct ListSeparator { state_type: PhantomData, } @@ -531,14 +531,14 @@ impl ListSeparator { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); div().h_px().w_full().bg(theme.border) } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct List { items: Vec>, empty_message: SharedString, @@ -571,7 +571,7 @@ impl List { self } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let is_toggleable = self.toggleable != Toggleable::NotToggleable; let is_toggled = Toggleable::is_toggled(&self.toggleable); diff --git a/crates/ui2/src/components/modal.rs b/crates/ui2/src/components/modal.rs index c8fbfc0c6d..0d57013e5d 100644 --- a/crates/ui2/src/components/modal.rs +++ b/crates/ui2/src/components/modal.rs @@ -5,7 +5,7 @@ use smallvec::SmallVec; use crate::{h_stack, prelude::*, v_stack, Button, Icon, IconButton, Label}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Modal { id: ElementId, state_type: PhantomData, @@ -42,7 +42,7 @@ impl Modal { self } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); v_stack() diff --git a/crates/ui2/src/components/multi_buffer.rs b/crates/ui2/src/components/multi_buffer.rs index 86e89c896c..30fcb935bb 100644 --- a/crates/ui2/src/components/multi_buffer.rs +++ b/crates/ui2/src/components/multi_buffer.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{v_stack, Buffer, Icon, IconButton, Label}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct MultiBuffer { state_type: PhantomData, buffers: Vec>, @@ -17,7 +17,7 @@ impl MultiBuffer { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); v_stack() @@ -50,7 +50,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct MultiBufferStory { state_type: PhantomData, } @@ -62,7 +62,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/notification_toast.rs b/crates/ui2/src/components/notification_toast.rs index 6a1011207b..6460c2f693 100644 --- a/crates/ui2/src/components/notification_toast.rs +++ b/crates/ui2/src/components/notification_toast.rs @@ -4,7 +4,7 @@ use gpui2::rems; use crate::{h_stack, prelude::*, Icon}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct NotificationToast { state_type: PhantomData, label: SharedString, @@ -28,7 +28,7 @@ impl NotificationToast { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); h_stack() diff --git a/crates/ui2/src/components/notifications_panel.rs b/crates/ui2/src/components/notifications_panel.rs index 44af3696c2..39ec9ea73f 100644 --- a/crates/ui2/src/components/notifications_panel.rs +++ b/crates/ui2/src/components/notifications_panel.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::{prelude::*, static_new_notification_items, static_read_notification_items}; use crate::{List, ListHeader}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct NotificationsPanel { id: ElementId, state_type: PhantomData, @@ -17,7 +17,7 @@ impl NotificationsPanel { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); div() @@ -58,7 +58,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct NotificationsPanelStory { state_type: PhantomData, } @@ -70,7 +70,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, NotificationsPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/palette.rs b/crates/ui2/src/components/palette.rs index 5b52f41aec..56928d4192 100644 --- a/crates/ui2/src/components/palette.rs +++ b/crates/ui2/src/components/palette.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{h_stack, v_stack, Keybinding, Label, LabelColor}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Palette { id: ElementId, state_type: PhantomData, @@ -46,7 +46,7 @@ impl Palette { self } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); v_stack() @@ -101,7 +101,7 @@ impl Palette { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct PaletteItem { pub label: SharedString, pub sublabel: Option, @@ -135,7 +135,7 @@ impl PaletteItem { self } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .flex() .flex_row() @@ -160,7 +160,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct PaletteStory { state_type: PhantomData, } @@ -172,7 +172,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, Palette>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index e6bca5afa7..63c694a7a3 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -40,7 +40,7 @@ pub enum PanelSide { use std::collections::HashSet; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Panel { id: ElementId, state_type: PhantomData, @@ -96,7 +96,7 @@ impl Panel { self } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let current_size = self.width.unwrap_or(self.initial_width); @@ -136,7 +136,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct PanelStory { state_type: PhantomData, } @@ -148,7 +148,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, Panel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index 118bb5f197..fafa2dd2a1 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -12,7 +12,7 @@ pub enum SplitDirection { Vertical, } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Pane { id: ElementId, size: Size, @@ -44,7 +44,7 @@ impl Pane { self } - fn render(self, view: &mut V, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, view: &mut V, cx: &mut ViewContext) -> impl Component { div() .id(self.id.clone()) .flex() @@ -75,7 +75,7 @@ impl ParentElement for Pane { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct PaneGroup { state_type: PhantomData, groups: Vec>, @@ -102,7 +102,7 @@ impl PaneGroup { } } - fn render(mut self, view: &mut V, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, view: &mut V, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); if !self.panes.is_empty() { diff --git a/crates/ui2/src/components/player_stack.rs b/crates/ui2/src/components/player_stack.rs index 88b2833dda..f1a8df8218 100644 --- a/crates/ui2/src/components/player_stack.rs +++ b/crates/ui2/src/components/player_stack.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{Avatar, Facepile, PlayerWithCallStatus}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct PlayerStack { state_type: PhantomData, player_with_call_status: PlayerWithCallStatus, @@ -17,7 +17,7 @@ impl PlayerStack { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let player = self.player_with_call_status.get_player(); self.player_with_call_status.get_call_status(); diff --git a/crates/ui2/src/components/project_panel.rs b/crates/ui2/src/components/project_panel.rs index 5771f996c5..e0791ab323 100644 --- a/crates/ui2/src/components/project_panel.rs +++ b/crates/ui2/src/components/project_panel.rs @@ -5,7 +5,7 @@ use crate::{ static_project_panel_project_items, static_project_panel_single_items, Input, List, ListHeader, }; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ProjectPanel { id: ElementId, state_type: PhantomData, @@ -19,7 +19,7 @@ impl ProjectPanel { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); div() @@ -67,7 +67,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct ProjectPanelStory { state_type: PhantomData, } @@ -79,7 +79,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, ProjectPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/recent_projects.rs b/crates/ui2/src/components/recent_projects.rs index d29caa2fd2..94d4c467f8 100644 --- a/crates/ui2/src/components/recent_projects.rs +++ b/crates/ui2/src/components/recent_projects.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{OrderMethod, Palette, PaletteItem}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct RecentProjects { id: ElementId, state_type: PhantomData, @@ -17,7 +17,7 @@ impl RecentProjects { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().id(self.id.clone()).child( Palette::new("palette") .items(vec![ @@ -44,7 +44,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct RecentProjectsStory { state_type: PhantomData, } @@ -56,7 +56,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, RecentProjects>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/status_bar.rs b/crates/ui2/src/components/status_bar.rs index 4ea0fe4eeb..e2fcfe9e02 100644 --- a/crates/ui2/src/components/status_bar.rs +++ b/crates/ui2/src/components/status_bar.rs @@ -28,8 +28,8 @@ impl Default for ToolGroup { } } -#[derive(IntoAnyElement)] -#[element(view_type = "Workspace")] +#[derive(Component)] +#[component(view_type = "Workspace")] pub struct StatusBar { left_tools: Option, right_tools: Option, @@ -86,7 +86,7 @@ impl StatusBar { self, view: &mut Workspace, cx: &mut ViewContext, - ) -> impl IntoAnyElement { + ) -> impl Component { let theme = theme(cx); div() @@ -105,7 +105,7 @@ impl StatusBar { &self, workspace: &mut Workspace, cx: &WindowContext, - ) -> impl IntoAnyElement { + ) -> impl Component { div() .flex() .items_center() @@ -136,7 +136,7 @@ impl StatusBar { &self, workspace: &mut Workspace, cx: &WindowContext, - ) -> impl IntoAnyElement { + ) -> impl Component { div() .flex() .items_center() diff --git a/crates/ui2/src/components/tab.rs b/crates/ui2/src/components/tab.rs index 02a2420580..63cdd55b76 100644 --- a/crates/ui2/src/components/tab.rs +++ b/crates/ui2/src/components/tab.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{Icon, IconColor, IconElement, Label, LabelColor}; -#[derive(IntoAnyElement, Clone)] +#[derive(Component, Clone)] pub struct Tab { state_type: PhantomData, id: ElementId, @@ -81,7 +81,7 @@ impl Tab { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict; let is_deleted = self.fs_status == FileSystemStatus::Deleted; @@ -176,7 +176,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct TabStory { state_type: PhantomData, } @@ -188,7 +188,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let git_statuses = GitStatus::iter(); let fs_statuses = FileSystemStatus::iter(); diff --git a/crates/ui2/src/components/tab_bar.rs b/crates/ui2/src/components/tab_bar.rs index 38dd9edade..344baaab4b 100644 --- a/crates/ui2/src/components/tab_bar.rs +++ b/crates/ui2/src/components/tab_bar.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{Icon, IconButton, Tab}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct TabBar { id: ElementId, state_type: PhantomData, @@ -27,7 +27,7 @@ impl TabBar { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let (can_navigate_back, can_navigate_forward) = self.can_navigate; @@ -100,7 +100,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct TabBarStory { state_type: PhantomData, } @@ -112,7 +112,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, TabBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/terminal.rs b/crates/ui2/src/components/terminal.rs index 55ab3e02fc..1f00a50685 100644 --- a/crates/ui2/src/components/terminal.rs +++ b/crates/ui2/src/components/terminal.rs @@ -5,7 +5,7 @@ use gpui2::{relative, rems, Size}; use crate::prelude::*; use crate::{Icon, IconButton, Pane, Tab}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Terminal { state_type: PhantomData, } @@ -17,7 +17,7 @@ impl Terminal { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let can_navigate_back = true; @@ -93,7 +93,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct TerminalStory { state_type: PhantomData, } @@ -105,7 +105,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, Terminal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/theme_selector.rs b/crates/ui2/src/components/theme_selector.rs index 1851aea954..e0865c3bcb 100644 --- a/crates/ui2/src/components/theme_selector.rs +++ b/crates/ui2/src/components/theme_selector.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use crate::prelude::*; use crate::{OrderMethod, Palette, PaletteItem}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ThemeSelector { id: ElementId, state_type: PhantomData, @@ -17,7 +17,7 @@ impl ThemeSelector { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().child( Palette::new(self.id.clone()) .items(vec![ @@ -49,7 +49,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct ThemeSelectorStory { state_type: PhantomData, } @@ -61,7 +61,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, ThemeSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/title_bar.rs b/crates/ui2/src/components/title_bar.rs index a20c7877b2..2d080ac649 100644 --- a/crates/ui2/src/components/title_bar.rs +++ b/crates/ui2/src/components/title_bar.rs @@ -87,7 +87,7 @@ impl TitleBar { ) } - fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(&mut self, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let settings = user_settings(cx); @@ -204,7 +204,7 @@ mod stories { ) } - fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(&mut self, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, TitleBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/toast.rs b/crates/ui2/src/components/toast.rs index 268042144b..78bb467aa6 100644 --- a/crates/ui2/src/components/toast.rs +++ b/crates/ui2/src/components/toast.rs @@ -22,7 +22,7 @@ pub enum ToastOrigin { /// they are actively showing the a process in progress. /// /// Only one toast may be visible at a time. -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Toast { origin: ToastOrigin, children: SmallVec<[AnyElement; 2]>, @@ -36,7 +36,7 @@ impl Toast { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let mut div = div(); @@ -78,7 +78,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct ToastStory { state_type: PhantomData, } @@ -90,7 +90,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, Toast>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/toolbar.rs b/crates/ui2/src/components/toolbar.rs index e18c81314d..3f629f93ad 100644 --- a/crates/ui2/src/components/toolbar.rs +++ b/crates/ui2/src/components/toolbar.rs @@ -6,7 +6,7 @@ use crate::prelude::*; #[derive(Clone)] pub struct ToolbarItem {} -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Toolbar { left_items: SmallVec<[AnyElement; 2]>, right_items: SmallVec<[AnyElement; 2]>, @@ -20,41 +20,41 @@ impl Toolbar { } } - pub fn left_item(mut self, child: impl IntoAnyElement) -> Self + pub fn left_item(mut self, child: impl Component) -> Self where Self: Sized, { - self.left_items.push(child.into_any()); + self.left_items.push(child.render()); self } - pub fn left_items(mut self, iter: impl IntoIterator>) -> Self + pub fn left_items(mut self, iter: impl IntoIterator>) -> Self where Self: Sized, { self.left_items - .extend(iter.into_iter().map(|item| item.into_any())); + .extend(iter.into_iter().map(|item| item.render())); self } - pub fn right_item(mut self, child: impl IntoAnyElement) -> Self + pub fn right_item(mut self, child: impl Component) -> Self where Self: Sized, { - self.right_items.push(child.into_any()); + self.right_items.push(child.render()); self } - pub fn right_items(mut self, iter: impl IntoIterator>) -> Self + pub fn right_items(mut self, iter: impl IntoIterator>) -> Self where Self: Sized, { self.right_items - .extend(iter.into_iter().map(|item| item.into_any())); + .extend(iter.into_iter().map(|item| item.render())); self } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); div() @@ -80,7 +80,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct ToolbarStory { state_type: PhantomData, } @@ -92,7 +92,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/traffic_lights.rs b/crates/ui2/src/components/traffic_lights.rs index cfe589b463..25b6d535c5 100644 --- a/crates/ui2/src/components/traffic_lights.rs +++ b/crates/ui2/src/components/traffic_lights.rs @@ -9,7 +9,7 @@ enum TrafficLightColor { Green, } -#[derive(IntoAnyElement)] +#[derive(Component)] struct TrafficLight { state_type: PhantomData, color: TrafficLightColor, @@ -25,7 +25,7 @@ impl TrafficLight { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let fill = match (self.window_has_focus, self.color) { @@ -39,7 +39,7 @@ impl TrafficLight { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct TrafficLights { state_type: PhantomData, window_has_focus: bool, @@ -58,7 +58,7 @@ impl TrafficLights { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .flex() .items_center() @@ -87,7 +87,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct TrafficLightsStory { state_type: PhantomData, } @@ -99,7 +99,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, TrafficLights>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index 34158c9918..e979de6d7c 100644 --- a/crates/ui2/src/components/workspace.rs +++ b/crates/ui2/src/components/workspace.rs @@ -174,7 +174,7 @@ impl Workspace { view(cx.entity(|cx| Self::new(cx)), Self::render) } - pub fn render(&mut self, cx: &mut ViewContext) -> impl IntoAnyElement { + pub fn render(&mut self, cx: &mut ViewContext) -> impl Component { let theme = old_theme(cx).clone(); // HACK: This should happen inside of `debug_toggle_user_settings`, but diff --git a/crates/ui2/src/elements/avatar.rs b/crates/ui2/src/elements/avatar.rs index 7d2e91ae8c..53f3dab58a 100644 --- a/crates/ui2/src/elements/avatar.rs +++ b/crates/ui2/src/elements/avatar.rs @@ -4,7 +4,7 @@ use gpui2::img; use crate::prelude::*; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Avatar { state_type: PhantomData, src: SharedString, @@ -25,7 +25,7 @@ impl Avatar { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let mut img = img(); @@ -51,7 +51,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct AvatarStory { state_type: PhantomData, } @@ -63,7 +63,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, Avatar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index 843a786aff..7c4290bd54 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -61,7 +61,7 @@ impl Default for ButtonHandlers { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Button { state_type: PhantomData, disabled: bool, @@ -150,7 +150,7 @@ impl Button { self.icon.map(|i| IconElement::new(i).color(icon_color)) } - pub fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + pub fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let icon_color = self.icon_color(); let mut button = h_stack() @@ -193,7 +193,7 @@ impl Button { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ButtonGroup { state_type: PhantomData, buttons: Vec>, @@ -207,7 +207,7 @@ impl ButtonGroup { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let mut el = h_stack().text_size(ui_size(cx, 1.)); for button in self.buttons { @@ -230,7 +230,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct ButtonStory { state_type: PhantomData, } @@ -242,7 +242,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let states = InteractionState::iter(); Story::container(cx) diff --git a/crates/ui2/src/elements/details.rs b/crates/ui2/src/elements/details.rs index 5f0676f9f4..84af82500b 100644 --- a/crates/ui2/src/elements/details.rs +++ b/crates/ui2/src/elements/details.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::{prelude::*, v_stack, ButtonGroup}; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Details { state_type: PhantomData, text: &'static str, @@ -30,7 +30,7 @@ impl Details { self } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); v_stack() @@ -54,7 +54,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct DetailsStory { state_type: PhantomData, } @@ -66,7 +66,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, Details>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/icon.rs b/crates/ui2/src/elements/icon.rs index 18d6050dd1..a29202aca0 100644 --- a/crates/ui2/src/elements/icon.rs +++ b/crates/ui2/src/elements/icon.rs @@ -148,7 +148,7 @@ impl Icon { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct IconElement { state_type: PhantomData, icon: Icon, @@ -176,7 +176,7 @@ impl IconElement { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let fill = self.color.color(cx); let svg_size = match self.size { IconSize::Small => ui_size(cx, 12. / 14.), @@ -202,7 +202,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct IconStory { state_type: PhantomData, } @@ -214,7 +214,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let icons = Icon::iter(); Story::container(cx) diff --git a/crates/ui2/src/elements/input.rs b/crates/ui2/src/elements/input.rs index 6a70c9cf79..d65dc62d65 100644 --- a/crates/ui2/src/elements/input.rs +++ b/crates/ui2/src/elements/input.rs @@ -11,7 +11,7 @@ pub enum InputVariant { Filled, } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Input { state_type: PhantomData, placeholder: SharedString, @@ -60,7 +60,7 @@ impl Input { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let (input_bg, input_hover_bg, input_active_bg) = match self.variant { @@ -120,7 +120,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct InputStory { state_type: PhantomData, } @@ -132,7 +132,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, Input>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/label.rs b/crates/ui2/src/elements/label.rs index 2d522a27b1..0910a59b55 100644 --- a/crates/ui2/src/elements/label.rs +++ b/crates/ui2/src/elements/label.rs @@ -48,7 +48,7 @@ pub enum LineHeightStyle { UILabel, } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct Label { state_type: PhantomData, label: SharedString, @@ -83,7 +83,7 @@ impl Label { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .when(self.strikethrough, |this| { this.relative().child( @@ -105,7 +105,7 @@ impl Label { } } -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct HighlightedLabel { state_type: PhantomData, label: SharedString, @@ -135,7 +135,7 @@ impl HighlightedLabel { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let highlight_color = theme.text_accent; @@ -211,7 +211,7 @@ mod stories { use super::*; - #[derive(IntoAnyElement)] + #[derive(Component)] pub struct LabelStory { state_type: PhantomData, } @@ -223,7 +223,7 @@ mod stories { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, Label>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/tool_divider.rs b/crates/ui2/src/elements/tool_divider.rs index b388894d1a..1c80bca05e 100644 --- a/crates/ui2/src/elements/tool_divider.rs +++ b/crates/ui2/src/elements/tool_divider.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::prelude::*; -#[derive(IntoAnyElement)] +#[derive(Component)] pub struct ToolDivider { state_type: PhantomData, } @@ -14,7 +14,7 @@ impl ToolDivider { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl IntoAnyElement { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); div().w_px().h_3().bg(theme.border) diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index 141c20c505..8098d3e40b 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -1,5 +1,5 @@ pub use gpui2::{ - div, Element, ElementId, IntoAnyElement, ParentElement, SharedString, StatefulInteractive, + div, Element, ElementId, Component, ParentElement, SharedString, StatefulInteractive, StatelessInteractive, Styled, ViewContext, WindowContext, }; diff --git a/crates/ui2/src/story.rs b/crates/ui2/src/story.rs index c4bf9c3caa..c35ddff0a9 100644 --- a/crates/ui2/src/story.rs +++ b/crates/ui2/src/story.rs @@ -21,7 +21,7 @@ impl Story { pub fn title( cx: &mut ViewContext, title: &str, - ) -> impl IntoAnyElement { + ) -> impl Component { let theme = theme(cx); div() @@ -30,16 +30,14 @@ impl Story { .child(title.to_owned()) } - pub fn title_for( - cx: &mut ViewContext, - ) -> impl IntoAnyElement { + pub fn title_for(cx: &mut ViewContext) -> impl Component { Self::title(cx, std::any::type_name::()) } pub fn label( cx: &mut ViewContext, label: &str, - ) -> impl IntoAnyElement { + ) -> impl Component { let theme = theme(cx); div() diff --git a/crates/ui2/src/theme.rs b/crates/ui2/src/theme.rs index b585140cf7..d8d924dbb0 100644 --- a/crates/ui2/src/theme.rs +++ b/crates/ui2/src/theme.rs @@ -1,5 +1,5 @@ use gpui2::{ - AnyElement, Bounds, Element, Hsla, IntoAnyElement, LayoutId, Pixels, Result, ViewContext, + AnyElement, Bounds, Component, Element, Hsla, LayoutId, Pixels, Result, ViewContext, WindowContext, }; use serde::{de::Visitor, Deserialize, Deserializer}; @@ -149,13 +149,13 @@ pub struct Themed { pub(crate) child: E, } -impl IntoAnyElement for Themed +impl Component for Themed where V: 'static, E: 'static + Element + Send + Sync, E::ElementState: Send + Sync, { - fn into_any(self) -> AnyElement { + fn render(self) -> AnyElement { AnyElement::new(self) } } From 065d26f5b2a241ef7f2e92bbcb87d7c52fe73fc0 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 26 Oct 2023 12:39:43 +0200 Subject: [PATCH 14/24] Get RPC2 tests passing Co-authored-by: Conrad Co-authored-by: Kyle --- Cargo.lock | 38 +++- Cargo.toml | 1 + crates/client2/Cargo.toml | 6 +- crates/client2/src/client2.rs | 8 +- crates/client2/src/user.rs | 2 +- crates/gpui2/src/platform/test/dispatcher.rs | 19 +- crates/language2/Cargo.toml | 3 +- crates/language2/src/buffer.rs | 4 +- crates/language2/src/language2.rs | 201 ++++++++++--------- crates/language2/src/proto.rs | 2 +- crates/project2/Cargo.toml | 4 +- crates/project2/src/worktree.rs | 6 +- crates/rpc2/Cargo.toml | 8 +- crates/rpc2/src/conn.rs | 16 +- crates/rpc2/src/peer.rs | 64 +++--- crates/rpc2/src/proto.rs | 4 +- crates/zed2/Cargo.toml | 2 +- 17 files changed, 210 insertions(+), 178 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34c1153ef8..754e56c090 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1481,7 +1481,7 @@ dependencies = [ "parking_lot 0.11.2", "postage", "rand 0.8.5", - "rpc", + "rpc2", "schemars", "serde", "serde_derive", @@ -4248,7 +4248,6 @@ dependencies = [ "collections", "ctor", "env_logger 0.9.3", - "fs", "futures 0.3.28", "fuzzy2", "git", @@ -4262,7 +4261,7 @@ dependencies = [ "postage", "rand 0.8.5", "regex", - "rpc", + "rpc2", "schemars", "serde", "serde_derive", @@ -6050,7 +6049,7 @@ dependencies = [ "pretty_assertions", "rand 0.8.5", "regex", - "rpc", + "rpc2", "schemars", "serde", "serde_derive", @@ -6802,6 +6801,35 @@ dependencies = [ "zstd", ] +[[package]] +name = "rpc2" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-lock", + "async-tungstenite", + "base64 0.13.1", + "clock", + "collections", + "ctor", + "env_logger 0.9.3", + "futures 0.3.28", + "gpui2", + "parking_lot 0.11.2", + "prost 0.8.0", + "prost-build", + "rand 0.8.5", + "rsa 0.4.0", + "serde", + "serde_derive", + "smol", + "smol-timeout", + "tempdir", + "tracing", + "util", + "zstd", +] + [[package]] name = "rsa" version = "0.4.0" @@ -10767,7 +10795,7 @@ dependencies = [ "postage", "rand 0.8.5", "regex", - "rpc", + "rpc2", "rsa 0.4.0", "rust-embed", "schemars", diff --git a/Cargo.toml b/Cargo.toml index 4687a99c88..0306ed249f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,7 @@ members = [ "crates/recent_projects", "crates/rope", "crates/rpc", + "crates/rpc2", "crates/search", "crates/settings", "crates/settings2", diff --git a/crates/client2/Cargo.toml b/crates/client2/Cargo.toml index 3203b71819..8a6edbb428 100644 --- a/crates/client2/Cargo.toml +++ b/crates/client2/Cargo.toml @@ -9,14 +9,14 @@ path = "src/client2.rs" doctest = false [features] -test-support = ["collections/test-support", "gpui2/test-support", "rpc/test-support"] +test-support = ["collections/test-support", "gpui2/test-support", "rpc2/test-support"] [dependencies] collections = { path = "../collections" } db2 = { path = "../db2" } gpui2 = { path = "../gpui2" } util = { path = "../util" } -rpc = { path = "../rpc" } +rpc2 = { path = "../rpc2" } text = { path = "../text" } settings2 = { path = "../settings2" } feature_flags2 = { path = "../feature_flags2" } @@ -47,6 +47,6 @@ url = "2.2" [dev-dependencies] collections = { path = "../collections", features = ["test-support"] } gpui2 = { path = "../gpui2", features = ["test-support"] } -rpc = { path = "../rpc", features = ["test-support"] } +rpc2 = { path = "../rpc2", features = ["test-support"] } settings = { path = "../settings", features = ["test-support"] } util = { path = "../util", features = ["test-support"] } diff --git a/crates/client2/src/client2.rs b/crates/client2/src/client2.rs index 6072f47397..215fcdf567 100644 --- a/crates/client2/src/client2.rs +++ b/crates/client2/src/client2.rs @@ -21,7 +21,7 @@ use lazy_static::lazy_static; use parking_lot::RwLock; use postage::watch; use rand::prelude::*; -use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, PeerId, RequestMessage}; +use rpc2::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, PeerId, RequestMessage}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings2::Settings; @@ -43,7 +43,7 @@ use util::channel::ReleaseChannel; use util::http::HttpClient; use util::{ResultExt, TryFutureExt}; -pub use rpc::*; +pub use rpc2::*; pub use telemetry::ClickhouseEvent; pub use user::*; @@ -975,7 +975,7 @@ impl Client { "Authorization", format!("{} {}", credentials.user_id, credentials.access_token), ) - .header("x-zed-protocol-version", rpc::PROTOCOL_VERSION); + .header("x-zed-protocol-version", rpc2::PROTOCOL_VERSION); let http = self.http.clone(); cx.executor().spawn(async move { @@ -1025,7 +1025,7 @@ impl Client { // zed server to encrypt the user's access token, so that it can'be intercepted by // any other app running on the user's device. let (public_key, private_key) = - rpc::auth::keypair().expect("failed to generate keypair for auth"); + rpc2::auth::keypair().expect("failed to generate keypair for auth"); let public_key_string = String::try_from(public_key).expect("failed to serialize public key for auth"); diff --git a/crates/client2/src/user.rs b/crates/client2/src/user.rs index 2aaae6dc85..41cf46ea8f 100644 --- a/crates/client2/src/user.rs +++ b/crates/client2/src/user.rs @@ -5,7 +5,7 @@ use feature_flags2::FeatureFlagAppExt; use futures::{channel::mpsc, future, AsyncReadExt, Future, StreamExt}; use gpui2::{AsyncAppContext, EventEmitter, Handle, ImageData, ModelContext, Task}; use postage::{sink::Sink, watch}; -use rpc::proto::{RequestMessage, UsersResponse}; +use rpc2::proto::{RequestMessage, UsersResponse}; use std::sync::{Arc, Weak}; use text::ReplicaId; use util::http::HttpClient; diff --git a/crates/gpui2/src/platform/test/dispatcher.rs b/crates/gpui2/src/platform/test/dispatcher.rs index 746a5ed0c0..02873f8e6e 100644 --- a/crates/gpui2/src/platform/test/dispatcher.rs +++ b/crates/gpui2/src/platform/test/dispatcher.rs @@ -1,6 +1,6 @@ use crate::PlatformDispatcher; use async_task::Runnable; -use collections::{BTreeMap, HashMap, VecDeque}; +use collections::{HashMap, VecDeque}; use parking_lot::Mutex; use rand::prelude::*; use std::{ @@ -24,7 +24,7 @@ struct TestDispatcherState { random: StdRng, foreground: HashMap>, background: Vec, - delayed: BTreeMap, + delayed: Vec<(Instant, Runnable)>, time: Instant, is_main_thread: bool, next_id: TestDispatcherId, @@ -36,7 +36,7 @@ impl TestDispatcher { random, foreground: HashMap::default(), background: Vec::new(), - delayed: BTreeMap::new(), + delayed: Vec::new(), time: Instant::now(), is_main_thread: true, next_id: TestDispatcherId(1), @@ -112,17 +112,20 @@ impl PlatformDispatcher for TestDispatcher { fn dispatch_after(&self, duration: std::time::Duration, runnable: Runnable) { let mut state = self.state.lock(); let next_time = state.time + duration; - state.delayed.insert(next_time, runnable); + let ix = match state.delayed.binary_search_by_key(&next_time, |e| e.0) { + Ok(ix) | Err(ix) => ix, + }; + state.delayed.insert(ix, (next_time, runnable)); } fn poll(&self) -> bool { let mut state = self.state.lock(); - while let Some((deadline, _)) = state.delayed.first_key_value() { + while let Some((deadline, _)) = state.delayed.first() { if *deadline > state.time { break; } - let (_, runnable) = state.delayed.pop_first().unwrap(); + let (_, runnable) = state.delayed.remove(0); state.background.push(runnable); } @@ -134,8 +137,10 @@ impl PlatformDispatcher for TestDispatcher { let background_len = state.background.len(); if foreground_len == 0 && background_len == 0 { + eprintln!("no runnables to poll"); return false; } + eprintln!("runnables {} {}", foreground_len, background_len); let main_thread = state.random.gen_ratio( foreground_len as u32, @@ -145,6 +150,7 @@ impl PlatformDispatcher for TestDispatcher { state.is_main_thread = main_thread; let runnable = if main_thread { + eprintln!("running next main thread"); let state = &mut *state; let runnables = state .foreground @@ -155,6 +161,7 @@ impl PlatformDispatcher for TestDispatcher { runnables.pop_front().unwrap() } else { let ix = state.random.gen_range(0..background_len); + eprintln!("running background thread {ix}"); state.background.swap_remove(ix) }; diff --git a/crates/language2/Cargo.toml b/crates/language2/Cargo.toml index 77b195293b..a3e1bf3e2a 100644 --- a/crates/language2/Cargo.toml +++ b/crates/language2/Cargo.toml @@ -25,11 +25,10 @@ test-support = [ clock = { path = "../clock" } collections = { path = "../collections" } fuzzy2 = { path = "../fuzzy2" } -fs = { path = "../fs" } git = { path = "../git" } gpui2 = { path = "../gpui2" } lsp2 = { path = "../lsp2" } -rpc = { path = "../rpc" } +rpc2 = { path = "../rpc2" } settings2 = { path = "../settings2" } sum_tree = { path = "../sum_tree" } text = { path = "../text" } diff --git a/crates/language2/src/buffer.rs b/crates/language2/src/buffer.rs index a8b764abc9..54425cec47 100644 --- a/crates/language2/src/buffer.rs +++ b/crates/language2/src/buffer.rs @@ -226,7 +226,7 @@ pub trait File: Send + Sync { fn as_any(&self) -> &dyn Any; - fn to_proto(&self) -> rpc::proto::File; + fn to_proto(&self) -> rpc2::proto::File; } pub trait LocalFile: File { @@ -375,7 +375,7 @@ impl Buffer { file, ); this.text.set_line_ending(proto::deserialize_line_ending( - rpc::proto::LineEnding::from_i32(message.line_ending) + rpc2::proto::LineEnding::from_i32(message.line_ending) .ok_or_else(|| anyhow!("missing line_ending"))?, )); this.saved_version = proto::deserialize_version(&message.saved_version); diff --git a/crates/language2/src/language2.rs b/crates/language2/src/language2.rs index d21ebd572a..9edaa16046 100644 --- a/crates/language2/src/language2.rs +++ b/crates/language2/src/language2.rs @@ -1862,111 +1862,112 @@ pub fn range_from_lsp(range: lsp2::Range) -> Range> { start..end } -// #[cfg(test)] -// mod tests { -// use super::*; -// use gpui::TestAppContext; +#[cfg(test)] +mod tests { + use super::*; + use gpui2::TestAppContext; -// #[gpui::test(iterations = 10)] -// async fn test_first_line_pattern(cx: &mut TestAppContext) { -// let mut languages = LanguageRegistry::test(); -// languages.set_executor(cx.background()); -// let languages = Arc::new(languages); -// languages.register( -// "/javascript", -// LanguageConfig { -// name: "JavaScript".into(), -// path_suffixes: vec!["js".into()], -// first_line_pattern: Some(Regex::new(r"\bnode\b").unwrap()), -// ..Default::default() -// }, -// tree_sitter_typescript::language_tsx(), -// vec![], -// |_| Default::default(), -// ); + #[gpui2::test(iterations = 10)] + async fn test_first_line_pattern(cx: &mut TestAppContext) { + let mut languages = LanguageRegistry::test(); -// languages -// .language_for_file("the/script", None) -// .await -// .unwrap_err(); -// languages -// .language_for_file("the/script", Some(&"nothing".into())) -// .await -// .unwrap_err(); -// assert_eq!( -// languages -// .language_for_file("the/script", Some(&"#!/bin/env node".into())) -// .await -// .unwrap() -// .name() -// .as_ref(), -// "JavaScript" -// ); -// } + languages.set_executor(cx.executor().clone()); + let languages = Arc::new(languages); + languages.register( + "/javascript", + LanguageConfig { + name: "JavaScript".into(), + path_suffixes: vec!["js".into()], + first_line_pattern: Some(Regex::new(r"\bnode\b").unwrap()), + ..Default::default() + }, + tree_sitter_typescript::language_tsx(), + vec![], + |_| Default::default(), + ); -// #[gpui::test(iterations = 10)] -// async fn test_language_loading(cx: &mut TestAppContext) { -// let mut languages = LanguageRegistry::test(); -// languages.set_executor(cx.background()); -// let languages = Arc::new(languages); -// languages.register( -// "/JSON", -// LanguageConfig { -// name: "JSON".into(), -// path_suffixes: vec!["json".into()], -// ..Default::default() -// }, -// tree_sitter_json::language(), -// vec![], -// |_| Default::default(), -// ); -// languages.register( -// "/rust", -// LanguageConfig { -// name: "Rust".into(), -// path_suffixes: vec!["rs".into()], -// ..Default::default() -// }, -// tree_sitter_rust::language(), -// vec![], -// |_| Default::default(), -// ); -// assert_eq!( -// languages.language_names(), -// &[ -// "JSON".to_string(), -// "Plain Text".to_string(), -// "Rust".to_string(), -// ] -// ); + languages + .language_for_file("the/script", None) + .await + .unwrap_err(); + languages + .language_for_file("the/script", Some(&"nothing".into())) + .await + .unwrap_err(); + assert_eq!( + languages + .language_for_file("the/script", Some(&"#!/bin/env node".into())) + .await + .unwrap() + .name() + .as_ref(), + "JavaScript" + ); + } -// let rust1 = languages.language_for_name("Rust"); -// let rust2 = languages.language_for_name("Rust"); + #[gpui2::test(iterations = 10)] + async fn test_language_loading(cx: &mut TestAppContext) { + let mut languages = LanguageRegistry::test(); + languages.set_executor(cx.executor().clone()); + let languages = Arc::new(languages); + languages.register( + "/JSON", + LanguageConfig { + name: "JSON".into(), + path_suffixes: vec!["json".into()], + ..Default::default() + }, + tree_sitter_json::language(), + vec![], + |_| Default::default(), + ); + languages.register( + "/rust", + LanguageConfig { + name: "Rust".into(), + path_suffixes: vec!["rs".into()], + ..Default::default() + }, + tree_sitter_rust::language(), + vec![], + |_| Default::default(), + ); + assert_eq!( + languages.language_names(), + &[ + "JSON".to_string(), + "Plain Text".to_string(), + "Rust".to_string(), + ] + ); -// // Ensure language is still listed even if it's being loaded. -// assert_eq!( -// languages.language_names(), -// &[ -// "JSON".to_string(), -// "Plain Text".to_string(), -// "Rust".to_string(), -// ] -// ); + let rust1 = languages.language_for_name("Rust"); + let rust2 = languages.language_for_name("Rust"); -// let (rust1, rust2) = futures::join!(rust1, rust2); -// assert!(Arc::ptr_eq(&rust1.unwrap(), &rust2.unwrap())); + // Ensure language is still listed even if it's being loaded. + assert_eq!( + languages.language_names(), + &[ + "JSON".to_string(), + "Plain Text".to_string(), + "Rust".to_string(), + ] + ); -// // Ensure language is still listed even after loading it. -// assert_eq!( -// languages.language_names(), -// &[ -// "JSON".to_string(), -// "Plain Text".to_string(), -// "Rust".to_string(), -// ] -// ); + let (rust1, rust2) = futures::join!(rust1, rust2); + assert!(Arc::ptr_eq(&rust1.unwrap(), &rust2.unwrap())); -// // Loading an unknown language returns an error. -// assert!(languages.language_for_name("Unknown").await.is_err()); -// } -// } + // Ensure language is still listed even after loading it. + assert_eq!( + languages.language_names(), + &[ + "JSON".to_string(), + "Plain Text".to_string(), + "Rust".to_string(), + ] + ); + + // Loading an unknown language returns an error. + assert!(languages.language_for_name("Unknown").await.is_err()); + } +} diff --git a/crates/language2/src/proto.rs b/crates/language2/src/proto.rs index e23711e328..f90bb94742 100644 --- a/crates/language2/src/proto.rs +++ b/crates/language2/src/proto.rs @@ -5,7 +5,7 @@ use crate::{ use anyhow::{anyhow, Result}; use clock::ReplicaId; use lsp2::{DiagnosticSeverity, LanguageServerId}; -use rpc::proto; +use rpc2::proto; use std::{ops::Range, sync::Arc}; use text::*; diff --git a/crates/project2/Cargo.toml b/crates/project2/Cargo.toml index 28b9826bd4..98bf9b62be 100644 --- a/crates/project2/Cargo.toml +++ b/crates/project2/Cargo.toml @@ -34,7 +34,7 @@ language2 = { path = "../language2" } lsp2 = { path = "../lsp2" } node_runtime = { path = "../node_runtime" } prettier2 = { path = "../prettier2" } -rpc = { path = "../rpc" } +rpc2 = { path = "../rpc2" } settings2 = { path = "../settings2" } sum_tree = { path = "../sum_tree" } terminal2 = { path = "../terminal2" } @@ -78,7 +78,7 @@ lsp2 = { path = "../lsp2", features = ["test-support"] } settings2 = { path = "../settings2", features = ["test-support"] } prettier2 = { path = "../prettier2", features = ["test-support"] } util = { path = "../util", features = ["test-support"] } -rpc = { path = "../rpc", features = ["test-support"] } +rpc2 = { path = "../rpc2", features = ["test-support"] } git2.workspace = true tempdir.workspace = true unindent.workspace = true diff --git a/crates/project2/src/worktree.rs b/crates/project2/src/worktree.rs index c094f21db4..c1b762640b 100644 --- a/crates/project2/src/worktree.rs +++ b/crates/project2/src/worktree.rs @@ -2646,8 +2646,8 @@ impl language2::File for File { self } - fn to_proto(&self) -> rpc::proto::File { - rpc::proto::File { + fn to_proto(&self) -> rpc2::proto::File { + rpc2::proto::File { worktree_id: self.worktree.entity_id().as_u64(), entry_id: self.entry_id.to_proto(), path: self.path.to_string_lossy().into(), @@ -2713,7 +2713,7 @@ impl File { } pub fn from_proto( - proto: rpc::proto::File, + proto: rpc2::proto::File, worktree: Handle, cx: &AppContext, ) -> Result { diff --git a/crates/rpc2/Cargo.toml b/crates/rpc2/Cargo.toml index 3c307be4fb..f108af3d3f 100644 --- a/crates/rpc2/Cargo.toml +++ b/crates/rpc2/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Shared logic for communication between the Zed app and the zed.dev server" edition = "2021" -name = "rpc" +name = "rpc2" version = "0.1.0" publish = false @@ -10,12 +10,12 @@ path = "src/rpc.rs" doctest = false [features] -test-support = ["collections/test-support", "gpui/test-support"] +test-support = ["collections/test-support", "gpui2/test-support"] [dependencies] clock = { path = "../clock" } collections = { path = "../collections" } -gpui = { path = "../gpui", optional = true } +gpui2 = { path = "../gpui2", optional = true } util = { path = "../util" } anyhow.workspace = true async-lock = "2.4" @@ -37,7 +37,7 @@ prost-build = "0.9" [dev-dependencies] collections = { path = "../collections", features = ["test-support"] } -gpui = { path = "../gpui", features = ["test-support"] } +gpui2 = { path = "../gpui2", features = ["test-support"] } smol.workspace = true tempdir.workspace = true ctor.workspace = true diff --git a/crates/rpc2/src/conn.rs b/crates/rpc2/src/conn.rs index 450e36782e..902e9822d5 100644 --- a/crates/rpc2/src/conn.rs +++ b/crates/rpc2/src/conn.rs @@ -34,7 +34,7 @@ impl Connection { #[cfg(any(test, feature = "test-support"))] pub fn in_memory( - executor: std::sync::Arc, + executor: gpui2::Executor, ) -> (Self, Self, std::sync::Arc) { use std::sync::{ atomic::{AtomicBool, Ordering::SeqCst}, @@ -53,7 +53,7 @@ impl Connection { #[allow(clippy::type_complexity)] fn channel( killed: Arc, - executor: Arc, + executor: gpui2::Executor, ) -> ( Box>, Box>>, @@ -66,14 +66,12 @@ impl Connection { let tx = tx.sink_map_err(|error| anyhow!(error)).with({ let killed = killed.clone(); - let executor = Arc::downgrade(&executor); + let executor = executor.clone(); move |msg| { let killed = killed.clone(); let executor = executor.clone(); Box::pin(async move { - if let Some(executor) = executor.upgrade() { - executor.simulate_random_delay().await; - } + executor.simulate_random_delay().await; // Writes to a half-open TCP connection will error. if killed.load(SeqCst) { @@ -87,14 +85,12 @@ impl Connection { let rx = rx.then({ let killed = killed; - let executor = Arc::downgrade(&executor); + let executor = executor.clone(); move |msg| { let killed = killed.clone(); let executor = executor.clone(); Box::pin(async move { - if let Some(executor) = executor.upgrade() { - executor.simulate_random_delay().await; - } + executor.simulate_random_delay().await; // Reads from a half-open TCP connection will hang. if killed.load(SeqCst) { diff --git a/crates/rpc2/src/peer.rs b/crates/rpc2/src/peer.rs index 91b914f169..6dfb170f4c 100644 --- a/crates/rpc2/src/peer.rs +++ b/crates/rpc2/src/peer.rs @@ -342,7 +342,7 @@ impl Peer { pub fn add_test_connection( self: &Arc, connection: Connection, - executor: Arc, + executor: gpui2::Executor, ) -> ( ConnectionId, impl Future> + Send, @@ -557,7 +557,7 @@ mod tests { use super::*; use crate::TypedEnvelope; use async_tungstenite::tungstenite::Message as WebSocketMessage; - use gpui::TestAppContext; + use gpui2::TestAppContext; #[ctor::ctor] fn init_logger() { @@ -566,9 +566,9 @@ mod tests { } } - #[gpui::test(iterations = 50)] + #[gpui2::test(iterations = 50)] async fn test_request_response(cx: &mut TestAppContext) { - let executor = cx.foreground(); + let executor = cx.executor(); // create 2 clients connected to 1 server let server = Peer::new(0); @@ -576,18 +576,18 @@ mod tests { let client2 = Peer::new(0); let (client1_to_server_conn, server_to_client_1_conn, _kill) = - Connection::in_memory(cx.background()); + Connection::in_memory(cx.executor().clone()); let (client1_conn_id, io_task1, client1_incoming) = - client1.add_test_connection(client1_to_server_conn, cx.background()); + client1.add_test_connection(client1_to_server_conn, cx.executor().clone()); let (_, io_task2, server_incoming1) = - server.add_test_connection(server_to_client_1_conn, cx.background()); + server.add_test_connection(server_to_client_1_conn, cx.executor().clone()); let (client2_to_server_conn, server_to_client_2_conn, _kill) = - Connection::in_memory(cx.background()); + Connection::in_memory(cx.executor().clone()); let (client2_conn_id, io_task3, client2_incoming) = - client2.add_test_connection(client2_to_server_conn, cx.background()); + client2.add_test_connection(client2_to_server_conn, cx.executor().clone()); let (_, io_task4, server_incoming2) = - server.add_test_connection(server_to_client_2_conn, cx.background()); + server.add_test_connection(server_to_client_2_conn, cx.executor().clone()); executor.spawn(io_task1).detach(); executor.spawn(io_task2).detach(); @@ -662,27 +662,27 @@ mod tests { } } - #[gpui::test(iterations = 50)] + #[gpui2::test(iterations = 50)] async fn test_order_of_response_and_incoming(cx: &mut TestAppContext) { - let executor = cx.foreground(); + let executor = cx.executor(); let server = Peer::new(0); let client = Peer::new(0); let (client_to_server_conn, server_to_client_conn, _kill) = - Connection::in_memory(cx.background()); + Connection::in_memory(executor.clone()); let (client_to_server_conn_id, io_task1, mut client_incoming) = - client.add_test_connection(client_to_server_conn, cx.background()); + client.add_test_connection(client_to_server_conn, executor.clone()); + let (server_to_client_conn_id, io_task2, mut server_incoming) = - server.add_test_connection(server_to_client_conn, cx.background()); + server.add_test_connection(server_to_client_conn, executor.clone()); executor.spawn(io_task1).detach(); executor.spawn(io_task2).detach(); executor .spawn(async move { - let request = server_incoming - .next() - .await + let future = server_incoming.next().await; + let request = future .unwrap() .into_any() .downcast::>() @@ -760,18 +760,18 @@ mod tests { ); } - #[gpui::test(iterations = 50)] + #[gpui2::test(iterations = 50)] async fn test_dropping_request_before_completion(cx: &mut TestAppContext) { - let executor = cx.foreground(); + let executor = cx.executor().clone(); let server = Peer::new(0); let client = Peer::new(0); let (client_to_server_conn, server_to_client_conn, _kill) = - Connection::in_memory(cx.background()); + Connection::in_memory(cx.executor().clone()); let (client_to_server_conn_id, io_task1, mut client_incoming) = - client.add_test_connection(client_to_server_conn, cx.background()); + client.add_test_connection(client_to_server_conn, cx.executor().clone()); let (server_to_client_conn_id, io_task2, mut server_incoming) = - server.add_test_connection(server_to_client_conn, cx.background()); + server.add_test_connection(server_to_client_conn, cx.executor().clone()); executor.spawn(io_task1).detach(); executor.spawn(io_task2).detach(); @@ -858,7 +858,7 @@ mod tests { .detach(); // Allow the request to make some progress before dropping it. - cx.background().simulate_random_delay().await; + cx.executor().simulate_random_delay().await; drop(request1_task); request2_task.await; @@ -872,15 +872,15 @@ mod tests { ); } - #[gpui::test(iterations = 50)] + #[gpui2::test(iterations = 50)] async fn test_disconnect(cx: &mut TestAppContext) { - let executor = cx.foreground(); + let executor = cx.executor(); - let (client_conn, mut server_conn, _kill) = Connection::in_memory(cx.background()); + let (client_conn, mut server_conn, _kill) = Connection::in_memory(executor.clone()); let client = Peer::new(0); let (connection_id, io_handler, mut incoming) = - client.add_test_connection(client_conn, cx.background()); + client.add_test_connection(client_conn, executor.clone()); let (io_ended_tx, io_ended_rx) = oneshot::channel(); executor @@ -908,14 +908,14 @@ mod tests { .is_err()); } - #[gpui::test(iterations = 50)] + #[gpui2::test(iterations = 50)] async fn test_io_error(cx: &mut TestAppContext) { - let executor = cx.foreground(); - let (client_conn, mut server_conn, _kill) = Connection::in_memory(cx.background()); + let executor = cx.executor(); + let (client_conn, mut server_conn, _kill) = Connection::in_memory(executor.clone()); let client = Peer::new(0); let (connection_id, io_handler, mut incoming) = - client.add_test_connection(client_conn, cx.background()); + client.add_test_connection(client_conn, executor.clone()); executor.spawn(io_handler).detach(); executor .spawn(async move { incoming.next().await }) diff --git a/crates/rpc2/src/proto.rs b/crates/rpc2/src/proto.rs index f0d7937f6f..c1a7af3e4d 100644 --- a/crates/rpc2/src/proto.rs +++ b/crates/rpc2/src/proto.rs @@ -616,7 +616,7 @@ pub fn split_worktree_update( mod tests { use super::*; - #[gpui::test] + #[gpui2::test] async fn test_buffer_size() { let (tx, rx) = futures::channel::mpsc::unbounded(); let mut sink = MessageStream::new(tx.sink_map_err(|_| anyhow!(""))); @@ -648,7 +648,7 @@ mod tests { assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN); } - #[gpui::test] + #[gpui2::test] fn test_converting_peer_id_from_and_to_u64() { let peer_id = PeerId { owner_id: 10, diff --git a/crates/zed2/Cargo.toml b/crates/zed2/Cargo.toml index baeea223f3..9351656d80 100644 --- a/crates/zed2/Cargo.toml +++ b/crates/zed2/Cargo.toml @@ -57,7 +57,7 @@ node_runtime = { path = "../node_runtime" } # project_symbols = { path = "../project_symbols" } # quick_action_bar = { path = "../quick_action_bar" } # recent_projects = { path = "../recent_projects" } -rpc = { path = "../rpc" } +rpc2 = { path = "../rpc2" } settings2 = { path = "../settings2" } feature_flags = { path = "../feature_flags" } sum_tree = { path = "../sum_tree" } From f4cff697297198a46c0a8387e45ed20fa1304097 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Oct 2023 13:18:58 +0200 Subject: [PATCH 15/24] WIP: Macro not working fully yet --- crates/gpui2_macros/src/derive_component.rs | 22 +++++++++++++++++--- crates/ui2/src/components/assistant_panel.rs | 16 ++++++-------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/crates/gpui2_macros/src/derive_component.rs b/crates/gpui2_macros/src/derive_component.rs index 45f4b44c85..6c0384c95a 100644 --- a/crates/gpui2_macros/src/derive_component.rs +++ b/crates/gpui2_macros/src/derive_component.rs @@ -1,9 +1,21 @@ use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, DeriveInput}; +use syn::{parse_macro_input, parse_quote, DeriveInput}; pub fn derive_component(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as DeriveInput); + let mut ast = parse_macro_input!(input as DeriveInput); + + if !ast + .generics + .params + .iter() + .any(|param| matches!(param, syn::GenericParam::Type(_))) + { + ast.generics.params.push(parse_quote! { + V: 'static + }); + } + let name = &ast.ident; let generics = &ast.generics; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); @@ -37,7 +49,7 @@ pub fn derive_component(input: TokenStream) -> TokenStream { if let Some(syn::GenericParam::Type(type_param)) = generics.params.first() { type_param.ident.clone() } else { - panic!("Expected first type parameter"); + panic!("Expected first type parameter to be a view type"); } }); @@ -50,5 +62,9 @@ pub fn derive_component(input: TokenStream) -> TokenStream { } }; + if name == "AssistantPanelStory" { + println!("Expanded tokens: {}", expanded.to_string()); + } + TokenStream::from(expanded) } diff --git a/crates/ui2/src/components/assistant_panel.rs b/crates/ui2/src/components/assistant_panel.rs index c07723cedb..c5eeb22a4c 100644 --- a/crates/ui2/src/components/assistant_panel.rs +++ b/crates/ui2/src/components/assistant_panel.rs @@ -69,7 +69,7 @@ impl AssistantPanel { .overflow_y_scroll() .child(Label::new("Is this thing on?")), ) - .render()]) + .renderinto_any()]) .side(self.current_side) .width(AbsoluteLength::Rems(rems(32.))) } @@ -85,20 +85,16 @@ mod stories { use super::*; #[derive(Component)] - pub struct AssistantPanelStory { - state_type: PhantomData, - } + pub struct AssistantPanelStory {} - impl AssistantPanelStory { + impl AssistantPanelStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self {} } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, AssistantPanel>(cx)) + .child(Story::title_for::<_, AssistantPanel>(cx)) .child(Story::label(cx, "Default")) .child(AssistantPanel::new("assistant-panel")) } From 8a0fb668f726200a5d37fdc5d84bc2e6a10aadbe Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 26 Oct 2023 13:50:24 +0200 Subject: [PATCH 16/24] Capture language server stderr during startup/init and log if failure zed2 electric boogaloo --- Cargo.lock | 2 ++ crates/copilot2/Cargo.toml | 1 + crates/copilot2/src/copilot2.rs | 12 ++++++++++-- crates/language2/src/language2.rs | 20 ++++++++++---------- crates/lsp2/src/lsp2.rs | 14 +++++++++++++- crates/prettier2/Cargo.toml | 1 + crates/prettier2/src/prettier2.rs | 1 + crates/project2/src/project2.rs | 30 ++++++++++++++++-------------- 8 files changed, 54 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbbcbc7914..ade49be3d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1836,6 +1836,7 @@ dependencies = [ "log", "lsp2", "node_runtime", + "parking_lot 0.11.2", "rpc", "serde", "serde_derive", @@ -5907,6 +5908,7 @@ dependencies = [ "log", "lsp2", "node_runtime", + "parking_lot 0.11.2", "serde", "serde_derive", "serde_json", diff --git a/crates/copilot2/Cargo.toml b/crates/copilot2/Cargo.toml index 161a9f3bd8..f83824d808 100644 --- a/crates/copilot2/Cargo.toml +++ b/crates/copilot2/Cargo.toml @@ -36,6 +36,7 @@ serde.workspace = true serde_derive.workspace = true smol.workspace = true futures.workspace = true +parking_lot.workspace = true [dev-dependencies] clock = { path = "../clock" } diff --git a/crates/copilot2/src/copilot2.rs b/crates/copilot2/src/copilot2.rs index 834750b25d..149b01aa82 100644 --- a/crates/copilot2/src/copilot2.rs +++ b/crates/copilot2/src/copilot2.rs @@ -17,6 +17,7 @@ use language2::{ }; use lsp2::{LanguageServer, LanguageServerBinary, LanguageServerId}; use node_runtime::NodeRuntime; +use parking_lot::Mutex; use request::StatusNotification; use settings2::SettingsStore; use smol::{fs, io::BufReader, stream::StreamExt}; @@ -394,8 +395,15 @@ impl Copilot { path: node_path, arguments, }; - let server = - LanguageServer::new(new_server_id, binary, Path::new("/"), None, cx.clone())?; + + let server = LanguageServer::new( + Arc::new(Mutex::new(None)), + new_server_id, + binary, + Path::new("/"), + None, + cx.clone(), + )?; server .on_notification::( diff --git a/crates/language2/src/language2.rs b/crates/language2/src/language2.rs index d21ebd572a..d0dd7c4ff7 100644 --- a/crates/language2/src/language2.rs +++ b/crates/language2/src/language2.rs @@ -667,7 +667,7 @@ struct LanguageRegistryState { pub struct PendingLanguageServer { pub server_id: LanguageServerId, - pub task: Task>>, + pub task: Task>, pub container_dir: Option>, } @@ -906,6 +906,7 @@ impl LanguageRegistry { pub fn create_pending_language_server( self: &Arc, + stderr_capture: Arc>>, language: Arc, adapter: Arc, root_path: Arc, @@ -945,7 +946,7 @@ impl LanguageRegistry { }) .detach(); - Ok(Some(server)) + Ok(server) }); return Some(PendingLanguageServer { @@ -996,24 +997,23 @@ impl LanguageRegistry { }) .clone(); - let binary = match entry.await.log_err() { - Some(binary) => binary, - None => return Ok(None), + let binary = match entry.await { + Ok(binary) => binary, + Err(err) => anyhow::bail!("{err}"), }; if let Some(task) = adapter.will_start_server(&delegate, &mut cx) { - if task.await.log_err().is_none() { - return Ok(None); - } + task.await?; } - Ok(Some(lsp2::LanguageServer::new( + lsp2::LanguageServer::new( + stderr_capture, server_id, binary, &root_path, adapter.code_action_kinds(), cx, - )?)) + ) }) }; diff --git a/crates/lsp2/src/lsp2.rs b/crates/lsp2/src/lsp2.rs index f874d9f118..a6a9a4f639 100644 --- a/crates/lsp2/src/lsp2.rs +++ b/crates/lsp2/src/lsp2.rs @@ -136,6 +136,7 @@ struct Error { impl LanguageServer { pub fn new( + stderr_capture: Arc>>, server_id: LanguageServerId, binary: LanguageServerBinary, root_path: &Path, @@ -165,6 +166,7 @@ impl LanguageServer { stdin, stdout, Some(stderr), + stderr_capture, Some(server), root_path, code_action_kinds, @@ -197,6 +199,7 @@ impl LanguageServer { stdin: Stdin, stdout: Stdout, stderr: Option, + stderr_capture: Arc>>, server: Option, root_path: &Path, code_action_kinds: Option>, @@ -237,7 +240,8 @@ impl LanguageServer { let stderr_input_task = stderr .map(|stderr| { let io_handlers = io_handlers.clone(); - cx.spawn(|_| Self::handle_stderr(stderr, io_handlers).log_err()) + let stderr_captures = stderr_captures.clone(); + cx.spawn(|_| Self::handle_stderr(stderr, io_handlers, stderr_captures).log_err()) }) .unwrap_or_else(|| Task::Ready(Some(None))); let input_task = cx.spawn(|_| async move { @@ -360,12 +364,14 @@ impl LanguageServer { async fn handle_stderr( stderr: Stderr, io_handlers: Arc>>, + stderr_capture: Arc>>, ) -> anyhow::Result<()> where Stderr: AsyncRead + Unpin + Send + 'static, { let mut stderr = BufReader::new(stderr); let mut buffer = Vec::new(); + loop { buffer.clear(); stderr.read_until(b'\n', &mut buffer).await?; @@ -374,6 +380,10 @@ impl LanguageServer { for handler in io_handlers.lock().values_mut() { handler(IoKind::StdErr, message); } + + if let Some(stderr) = stderr_capture.lock().as_mut() { + stderr.push_str(message); + } } // Don't starve the main thread when receiving lots of messages at once. @@ -933,6 +943,7 @@ impl LanguageServer { stdin_writer, stdout_reader, None::, + Arc::new(Mutex::new(None)), None, Path::new("/"), None, @@ -945,6 +956,7 @@ impl LanguageServer { stdout_writer, stdin_reader, None::, + Arc::new(Mutex::new(None)), None, Path::new("/"), None, diff --git a/crates/prettier2/Cargo.toml b/crates/prettier2/Cargo.toml index 0fca004344..8defd40262 100644 --- a/crates/prettier2/Cargo.toml +++ b/crates/prettier2/Cargo.toml @@ -27,6 +27,7 @@ serde_derive.workspace = true serde_json.workspace = true anyhow.workspace = true futures.workspace = true +parking_lot.workspace = true [dev-dependencies] language2 = { path = "../language2", features = ["test-support"] } diff --git a/crates/prettier2/src/prettier2.rs b/crates/prettier2/src/prettier2.rs index 4e8d8b9070..ed22d23157 100644 --- a/crates/prettier2/src/prettier2.rs +++ b/crates/prettier2/src/prettier2.rs @@ -210,6 +210,7 @@ impl Prettier { .spawn(async move { node.binary_path().await }) .await?; let server = LanguageServer::new( + Arc::new(parking_lot::Mutex::new(None)), server_id, LanguageServerBinary { path: node_path, diff --git a/crates/project2/src/project2.rs b/crates/project2/src/project2.rs index a49a17a3b6..4e52992380 100644 --- a/crates/project2/src/project2.rs +++ b/crates/project2/src/project2.rs @@ -52,6 +52,7 @@ use lsp2::{ }; use lsp_command::*; use node_runtime::NodeRuntime; +use parking_lot::Mutex; use postage::watch; use prettier2::{LocateStart, Prettier, PRETTIER_SERVER_FILE, PRETTIER_SERVER_JS}; use project_settings::{LspSettings, ProjectSettings}; @@ -2778,7 +2779,9 @@ impl Project { return; } + let stderr_capture = Arc::new(Mutex::new(Some(String::new()))); let pending_server = match self.languages.create_pending_language_server( + stderr_capture.clone(), language.clone(), adapter.clone(), worktree_path, @@ -2824,10 +2827,14 @@ impl Project { .await; match result { - Ok(server) => server, + Ok(server) => { + stderr_capture.lock().take(); + server + } Err(err) => { log::error!("failed to start language server {:?}: {}", server_name, err); + log::error!("server stderr: {:?}", stderr_capture.lock().take()); if let Some(this) = this.upgrade() { if let Some(container_dir) = container_dir { @@ -2931,19 +2938,16 @@ impl Project { key: (WorktreeId, LanguageServerName), cx: &mut AsyncAppContext, ) -> Result>> { - let setup = Self::setup_pending_language_server( + let language_server = Self::setup_pending_language_server( this.clone(), initialization_options, pending_server, adapter.clone(), server_id, cx, - ); + ) + .await?; - let language_server = match setup.await? { - Some(language_server) => language_server, - None => return Ok(None), - }; let this = match this.upgrade() { Some(this) => this, None => return Err(anyhow!("failed to upgrade project handle")), @@ -2960,7 +2964,7 @@ impl Project { ) })??; - Ok(Some(language_server)) + Ok(language_server) } async fn setup_pending_language_server( @@ -2970,12 +2974,9 @@ impl Project { adapter: Arc, server_id: LanguageServerId, cx: &mut AsyncAppContext, - ) -> Result>> { + ) -> Result> { let workspace_config = cx.update(|cx| adapter.workspace_configuration(cx))?.await; - let language_server = match pending_server.task.await? { - Some(server) => server, - None => return Ok(None), - }; + let language_server = pending_server.task.await?; language_server .on_notification::({ @@ -3050,6 +3051,7 @@ impl Project { } }) .detach(); + language_server .on_request::({ let this = this.clone(); @@ -3138,7 +3140,7 @@ impl Project { ) .ok(); - Ok(Some(language_server)) + Ok(language_server) } fn insert_newly_running_language_server( From 0a04c5734baa51d3d93752861054f430f6400b09 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 26 Oct 2023 13:50:35 +0200 Subject: [PATCH 17/24] Update mouse position during file drag and drop --- crates/gpui2/src/window.rs | 33 ++++++++++++++++++------------ crates/ui2/src/components/panes.rs | 1 - 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 8b3aa7a117..fc9b8b8de8 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1,7 +1,7 @@ use crate::{ px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, - Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, ExternalPaths, - Edges, Effect, Element, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, + Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, + Element, EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, Modifiers, MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, @@ -899,6 +899,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { } InputEvent::FileDrop(file_drop) => match file_drop { FileDropEvent::Entered { position, files } => { + self.window.mouse_position = position; self.active_drag.get_or_insert_with(|| AnyDrag { drag_handle_view: None, cursor_offset: position, @@ -912,17 +913,23 @@ impl<'a, 'w> WindowContext<'a, 'w> { modifiers: Modifiers::default(), }) } - FileDropEvent::Pending { position } => InputEvent::MouseMove(MouseMoveEvent { - position, - pressed_button: Some(MouseButton::Left), - modifiers: Modifiers::default(), - }), - FileDropEvent::Submit { position } => InputEvent::MouseUp(MouseUpEvent { - button: MouseButton::Left, - position, - modifiers: Modifiers::default(), - click_count: 1, - }), + FileDropEvent::Pending { position } => { + self.window.mouse_position = position; + InputEvent::MouseMove(MouseMoveEvent { + position, + pressed_button: Some(MouseButton::Left), + modifiers: Modifiers::default(), + }) + } + FileDropEvent::Submit { position } => { + self.window.mouse_position = position; + InputEvent::MouseUp(MouseUpEvent { + button: MouseButton::Left, + position, + modifiers: Modifiers::default(), + click_count: 1, + }) + } FileDropEvent::Exited => InputEvent::MouseUp(MouseUpEvent { button: MouseButton::Left, position: Point::default(), diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index 77b6817d89..fd1ec56ae7 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -56,7 +56,6 @@ impl Pane { .children(self.children.drain(..)), ) .child( - // TODO kb! Figure out why we can't we see the red background when we drag a file over this div. div() .z_index(1) .id("drag-target") From 27d2accb517f3251527fca7726899a47553a8b74 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 26 Oct 2023 13:52:04 +0200 Subject: [PATCH 18/24] Fix the formatting --- crates/gpui2/src/color.rs | 3 --- crates/gpui2/src/svg_renderer.rs | 2 +- crates/ui2/src/components/workspace.rs | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/gpui2/src/color.rs b/crates/gpui2/src/color.rs index f8ae1567e3..db07259476 100644 --- a/crates/gpui2/src/color.rs +++ b/crates/gpui2/src/color.rs @@ -60,7 +60,6 @@ impl From for u32 { } } - struct RgbaVisitor; impl<'de> Visitor<'de> for RgbaVisitor { @@ -157,10 +156,8 @@ impl Hsla { } } - impl Eq for Hsla {} - pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla { Hsla { h: h.clamp(0., 1.), diff --git a/crates/gpui2/src/svg_renderer.rs b/crates/gpui2/src/svg_renderer.rs index 8fc68ede45..96e6658ab1 100644 --- a/crates/gpui2/src/svg_renderer.rs +++ b/crates/gpui2/src/svg_renderer.rs @@ -1,4 +1,4 @@ -use crate::{DevicePixels, IsZero, Result, SharedString, Size, AssetSource}; +use crate::{AssetSource, DevicePixels, IsZero, Result, SharedString, Size}; use anyhow::anyhow; use std::{hash::Hash, sync::Arc}; diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index ee913cb693..e31b21e592 100644 --- a/crates/ui2/src/components/workspace.rs +++ b/crates/ui2/src/components/workspace.rs @@ -3,13 +3,13 @@ use std::sync::Arc; use chrono::DateTime; use gpui2::{px, relative, rems, view, Context, Size, View}; -use crate::{prelude::*, NotificationsPanel}; use crate::{ - static_livestream, old_theme, user_settings_mut, v_stack, AssistantPanel, Button, ChatMessage, + old_theme, static_livestream, user_settings_mut, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel, CollabPanel, EditorPane, FakeSettings, Label, LanguageSelector, Pane, PaneGroup, Panel, PanelAllowedSides, PanelSide, ProjectPanel, SettingValue, SplitDirection, StatusBar, Terminal, TitleBar, Toast, ToastOrigin, }; +use crate::{prelude::*, NotificationsPanel}; #[derive(Clone)] pub struct Gpui2UiDebug { From c9c9db903d07c18c48fed86e3e9debb04783e54f Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 26 Oct 2023 14:20:25 +0200 Subject: [PATCH 19/24] Fix Component derive macro --- crates/gpui2_macros/src/derive_component.rs | 84 ++++++++++---------- crates/ui2/src/components/assistant_panel.rs | 4 +- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/crates/gpui2_macros/src/derive_component.rs b/crates/gpui2_macros/src/derive_component.rs index 6c0384c95a..97cfac1ae5 100644 --- a/crates/gpui2_macros/src/derive_component.rs +++ b/crates/gpui2_macros/src/derive_component.rs @@ -3,55 +3,29 @@ use quote::quote; use syn::{parse_macro_input, parse_quote, DeriveInput}; pub fn derive_component(input: TokenStream) -> TokenStream { - let mut ast = parse_macro_input!(input as DeriveInput); - - if !ast - .generics - .params - .iter() - .any(|param| matches!(param, syn::GenericParam::Type(_))) - { - ast.generics.params.push(parse_quote! { - V: 'static - }); - } - + let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident; - let generics = &ast.generics; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let specified_view_type = ast - .attrs - .iter() - .find(|attr| attr.path.is_ident("component")) - .and_then(|attr| { - if let Ok(syn::Meta::List(meta_list)) = attr.parse_meta() { - meta_list.nested.iter().find_map(|nested| { - if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = nested { - if nv.path.is_ident("view_type") { - if let syn::Lit::Str(lit_str) = &nv.lit { - return Some( - lit_str - .parse::() - .expect("Failed to parse view_type"), - ); - } - } - } - None - }) + let mut trait_generics = ast.generics.clone(); + let view_type = if let Some(view_type) = specified_view_type(&ast) { + quote! { #view_type } + } else { + if let Some(first_type_param) = ast.generics.params.iter().find_map(|param| { + if let syn::GenericParam::Type(type_param) = param { + Some(type_param.ident.clone()) } else { None } - }); - - let view_type = specified_view_type.unwrap_or_else(|| { - if let Some(syn::GenericParam::Type(type_param)) = generics.params.first() { - type_param.ident.clone() + }) { + quote! { #first_type_param } } else { - panic!("Expected first type parameter to be a view type"); + trait_generics.params.push(parse_quote! { V: 'static + Send + Sync }); + quote! { V } } - }); + }; + + let (impl_generics, _, where_clause) = trait_generics.split_for_impl(); + let (_, ty_generics, _) = ast.generics.split_for_impl(); let expanded = quote! { impl #impl_generics gpui2::Component<#view_type> for #name #ty_generics #where_clause { @@ -68,3 +42,29 @@ pub fn derive_component(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } + +fn specified_view_type(ast: &DeriveInput) -> Option { + let component_attr = ast + .attrs + .iter() + .find(|attr| attr.path.is_ident("component"))?; + + if let Ok(syn::Meta::List(meta_list)) = component_attr.parse_meta() { + meta_list.nested.iter().find_map(|nested| { + if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = nested { + if nv.path.is_ident("view_type") { + if let syn::Lit::Str(lit_str) = &nv.lit { + return Some( + lit_str + .parse::() + .expect("Failed to parse view_type"), + ); + } + } + } + None + }) + } else { + None + } +} diff --git a/crates/ui2/src/components/assistant_panel.rs b/crates/ui2/src/components/assistant_panel.rs index c5eeb22a4c..25f24f1483 100644 --- a/crates/ui2/src/components/assistant_panel.rs +++ b/crates/ui2/src/components/assistant_panel.rs @@ -69,7 +69,7 @@ impl AssistantPanel { .overflow_y_scroll() .child(Label::new("Is this thing on?")), ) - .renderinto_any()]) + .render()]) .side(self.current_side) .width(AbsoluteLength::Rems(rems(32.))) } @@ -92,7 +92,7 @@ mod stories { Self {} } - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title_for::<_, AssistantPanel>(cx)) .child(Story::label(cx, "Default")) From 69e5ecc01542052dffe22725e8b94ee69b4b9841 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 26 Oct 2023 14:43:28 +0200 Subject: [PATCH 20/24] Enable client tests * implement Executor::advance_clock Co-authored-by: Conrad Co-authored-by: Kyle Co-authored-by: Joseph --- crates/client2/src/client2.rs | 507 +++++++++---------- crates/client2/src/test.rs | 381 +++++++------- crates/gpui2/src/app/test_context.rs | 2 +- crates/gpui2/src/executor.rs | 20 +- crates/gpui2/src/platform/test/dispatcher.rs | 28 +- crates/gpui2/src/platform/test/platform.rs | 6 +- 6 files changed, 479 insertions(+), 465 deletions(-) diff --git a/crates/client2/src/client2.rs b/crates/client2/src/client2.rs index 215fcdf567..79b0205c91 100644 --- a/crates/client2/src/client2.rs +++ b/crates/client2/src/client2.rs @@ -1377,290 +1377,275 @@ pub fn decode_worktree_url(url: &str) -> Option<(u64, String)> { Some((id, access_token.to_string())) } -// #[cfg(test)] -// mod tests { -// use super::*; -// use crate::test::FakeServer; -// use gpui::{executor::Deterministic, TestAppContext}; -// use parking_lot::Mutex; -// use std::future; -// use util::http::FakeHttpClient; +#[cfg(test)] +mod tests { + use super::*; + use crate::test::FakeServer; -// #[gpui::test(iterations = 10)] -// async fn test_reconnection(cx: &mut TestAppContext) { -// cx.foreground().forbid_parking(); + use gpui2::{Context, Executor, TestAppContext}; + use parking_lot::Mutex; + use std::future; + use util::http::FakeHttpClient; -// let user_id = 5; -// let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); -// let server = FakeServer::for_client(user_id, &client, cx).await; -// let mut status = client.status(); -// assert!(matches!( -// status.next().await, -// Some(Status::Connected { .. }) -// )); -// assert_eq!(server.auth_count(), 1); + #[gpui2::test(iterations = 10)] + async fn test_reconnection(cx: &mut TestAppContext) { + let user_id = 5; + let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); + let server = FakeServer::for_client(user_id, &client, cx).await; + let mut status = client.status(); + assert!(matches!( + status.next().await, + Some(Status::Connected { .. }) + )); + assert_eq!(server.auth_count(), 1); -// server.forbid_connections(); -// server.disconnect(); -// while !matches!(status.next().await, Some(Status::ReconnectionError { .. })) {} + server.forbid_connections(); + server.disconnect(); + while !matches!(status.next().await, Some(Status::ReconnectionError { .. })) {} -// server.allow_connections(); -// cx.foreground().advance_clock(Duration::from_secs(10)); -// while !matches!(status.next().await, Some(Status::Connected { .. })) {} -// assert_eq!(server.auth_count(), 1); // Client reused the cached credentials when reconnecting + server.allow_connections(); + cx.executor().advance_clock(Duration::from_secs(10)); + while !matches!(status.next().await, Some(Status::Connected { .. })) {} + assert_eq!(server.auth_count(), 1); // Client reused the cached credentials when reconnecting -// server.forbid_connections(); -// server.disconnect(); -// while !matches!(status.next().await, Some(Status::ReconnectionError { .. })) {} + server.forbid_connections(); + server.disconnect(); + while !matches!(status.next().await, Some(Status::ReconnectionError { .. })) {} -// // Clear cached credentials after authentication fails -// server.roll_access_token(); -// server.allow_connections(); -// cx.foreground().advance_clock(Duration::from_secs(10)); -// while !matches!(status.next().await, Some(Status::Connected { .. })) {} -// assert_eq!(server.auth_count(), 2); // Client re-authenticated due to an invalid token -// } + // Clear cached credentials after authentication fails + server.roll_access_token(); + server.allow_connections(); + cx.executor().run_until_parked(); + cx.executor().advance_clock(Duration::from_secs(10)); + while !matches!(status.next().await, Some(Status::Connected { .. })) {} + assert_eq!(server.auth_count(), 2); // Client re-authenticated due to an invalid token + } -// #[gpui::test(iterations = 10)] -// async fn test_connection_timeout(deterministic: Arc, cx: &mut TestAppContext) { -// deterministic.forbid_parking(); + #[gpui2::test(iterations = 10)] + async fn test_connection_timeout(executor: Executor, cx: &mut TestAppContext) { + let user_id = 5; + let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); + let mut status = client.status(); -// let user_id = 5; -// let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); -// let mut status = client.status(); + // Time out when client tries to connect. + client.override_authenticate(move |cx| { + cx.executor().spawn(async move { + Ok(Credentials { + user_id, + access_token: "token".into(), + }) + }) + }); + client.override_establish_connection(|_, cx| { + cx.executor().spawn(async move { + future::pending::<()>().await; + unreachable!() + }) + }); + let auth_and_connect = cx.spawn({ + let client = client.clone(); + |cx| async move { client.authenticate_and_connect(false, &cx).await } + }); + executor.run_until_parked(); + assert!(matches!(status.next().await, Some(Status::Connecting))); -// // Time out when client tries to connect. -// client.override_authenticate(move |cx| { -// cx.foreground().spawn(async move { -// Ok(Credentials { -// user_id, -// access_token: "token".into(), -// }) -// }) -// }); -// client.override_establish_connection(|_, cx| { -// cx.foreground().spawn(async move { -// future::pending::<()>().await; -// unreachable!() -// }) -// }); -// let auth_and_connect = cx.spawn({ -// let client = client.clone(); -// |cx| async move { client.authenticate_and_connect(false, &cx).await } -// }); -// deterministic.run_until_parked(); -// assert!(matches!(status.next().await, Some(Status::Connecting))); + executor.advance_clock(CONNECTION_TIMEOUT); + assert!(matches!( + status.next().await, + Some(Status::ConnectionError { .. }) + )); + auth_and_connect.await.unwrap_err(); -// deterministic.advance_clock(CONNECTION_TIMEOUT); -// assert!(matches!( -// status.next().await, -// Some(Status::ConnectionError { .. }) -// )); -// auth_and_connect.await.unwrap_err(); + // Allow the connection to be established. + let server = FakeServer::for_client(user_id, &client, cx).await; + assert!(matches!( + status.next().await, + Some(Status::Connected { .. }) + )); -// // Allow the connection to be established. -// let server = FakeServer::for_client(user_id, &client, cx).await; -// assert!(matches!( -// status.next().await, -// Some(Status::Connected { .. }) -// )); + // Disconnect client. + server.forbid_connections(); + server.disconnect(); + while !matches!(status.next().await, Some(Status::ReconnectionError { .. })) {} -// // Disconnect client. -// server.forbid_connections(); -// server.disconnect(); -// while !matches!(status.next().await, Some(Status::ReconnectionError { .. })) {} + // Time out when re-establishing the connection. + server.allow_connections(); + client.override_establish_connection(|_, cx| { + cx.executor().spawn(async move { + future::pending::<()>().await; + unreachable!() + }) + }); + executor.advance_clock(2 * INITIAL_RECONNECTION_DELAY); + assert!(matches!( + status.next().await, + Some(Status::Reconnecting { .. }) + )); -// // Time out when re-establishing the connection. -// server.allow_connections(); -// client.override_establish_connection(|_, cx| { -// cx.foreground().spawn(async move { -// future::pending::<()>().await; -// unreachable!() -// }) -// }); -// deterministic.advance_clock(2 * INITIAL_RECONNECTION_DELAY); -// assert!(matches!( -// status.next().await, -// Some(Status::Reconnecting { .. }) -// )); + executor.advance_clock(CONNECTION_TIMEOUT); + assert!(matches!( + status.next().await, + Some(Status::ReconnectionError { .. }) + )); + } -// deterministic.advance_clock(CONNECTION_TIMEOUT); -// assert!(matches!( -// status.next().await, -// Some(Status::ReconnectionError { .. }) -// )); -// } + #[gpui2::test(iterations = 10)] + async fn test_authenticating_more_than_once(cx: &mut TestAppContext, executor: Executor) { + let auth_count = Arc::new(Mutex::new(0)); + let dropped_auth_count = Arc::new(Mutex::new(0)); + let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); + client.override_authenticate({ + let auth_count = auth_count.clone(); + let dropped_auth_count = dropped_auth_count.clone(); + move |cx| { + let auth_count = auth_count.clone(); + let dropped_auth_count = dropped_auth_count.clone(); + cx.executor().spawn(async move { + *auth_count.lock() += 1; + let _drop = util::defer(move || *dropped_auth_count.lock() += 1); + future::pending::<()>().await; + unreachable!() + }) + } + }); -// #[gpui::test(iterations = 10)] -// async fn test_authenticating_more_than_once( -// cx: &mut TestAppContext, -// deterministic: Arc, -// ) { -// cx.foreground().forbid_parking(); + let _authenticate = cx.spawn({ + let client = client.clone(); + move |cx| async move { client.authenticate_and_connect(false, &cx).await } + }); + executor.run_until_parked(); + assert_eq!(*auth_count.lock(), 1); + assert_eq!(*dropped_auth_count.lock(), 0); -// let auth_count = Arc::new(Mutex::new(0)); -// let dropped_auth_count = Arc::new(Mutex::new(0)); -// let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); -// client.override_authenticate({ -// let auth_count = auth_count.clone(); -// let dropped_auth_count = dropped_auth_count.clone(); -// move |cx| { -// let auth_count = auth_count.clone(); -// let dropped_auth_count = dropped_auth_count.clone(); -// cx.foreground().spawn(async move { -// *auth_count.lock() += 1; -// let _drop = util::defer(move || *dropped_auth_count.lock() += 1); -// future::pending::<()>().await; -// unreachable!() -// }) -// } -// }); + let _authenticate = cx.spawn({ + let client = client.clone(); + |cx| async move { client.authenticate_and_connect(false, &cx).await } + }); + executor.run_until_parked(); + assert_eq!(*auth_count.lock(), 2); + assert_eq!(*dropped_auth_count.lock(), 1); + } -// let _authenticate = cx.spawn(|cx| { -// let client = client.clone(); -// async move { client.authenticate_and_connect(false, &cx).await } -// }); -// deterministic.run_until_parked(); -// assert_eq!(*auth_count.lock(), 1); -// assert_eq!(*dropped_auth_count.lock(), 0); + #[test] + fn test_encode_and_decode_worktree_url() { + let url = encode_worktree_url(5, "deadbeef"); + assert_eq!(decode_worktree_url(&url), Some((5, "deadbeef".to_string()))); + assert_eq!( + decode_worktree_url(&format!("\n {}\t", url)), + Some((5, "deadbeef".to_string())) + ); + assert_eq!(decode_worktree_url("not://the-right-format"), None); + } -// let _authenticate = cx.spawn(|cx| { -// let client = client.clone(); -// async move { client.authenticate_and_connect(false, &cx).await } -// }); -// deterministic.run_until_parked(); -// assert_eq!(*auth_count.lock(), 2); -// assert_eq!(*dropped_auth_count.lock(), 1); -// } + #[gpui2::test] + async fn test_subscribing_to_entity(cx: &mut TestAppContext) { + let user_id = 5; + let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); + let server = FakeServer::for_client(user_id, &client, cx).await; -// #[test] -// fn test_encode_and_decode_worktree_url() { -// let url = encode_worktree_url(5, "deadbeef"); -// assert_eq!(decode_worktree_url(&url), Some((5, "deadbeef".to_string()))); -// assert_eq!( -// decode_worktree_url(&format!("\n {}\t", url)), -// Some((5, "deadbeef".to_string())) -// ); -// assert_eq!(decode_worktree_url("not://the-right-format"), None); -// } + let (done_tx1, mut done_rx1) = smol::channel::unbounded(); + let (done_tx2, mut done_rx2) = smol::channel::unbounded(); + client.add_model_message_handler( + move |model: Handle, _: TypedEnvelope, _, mut cx| { + match model.update(&mut cx, |model, _| model.id).unwrap() { + 1 => done_tx1.try_send(()).unwrap(), + 2 => done_tx2.try_send(()).unwrap(), + _ => unreachable!(), + } + async { Ok(()) } + }, + ); + let model1 = cx.entity(|_| Model { + id: 1, + subscription: None, + }); + let model2 = cx.entity(|_| Model { + id: 2, + subscription: None, + }); + let model3 = cx.entity(|_| Model { + id: 3, + subscription: None, + }); -// #[gpui::test] -// async fn test_subscribing_to_entity(cx: &mut TestAppContext) { -// cx.foreground().forbid_parking(); + let _subscription1 = client + .subscribe_to_entity(1) + .unwrap() + .set_model(&model1, &mut cx.to_async()); + let _subscription2 = client + .subscribe_to_entity(2) + .unwrap() + .set_model(&model2, &mut cx.to_async()); + // Ensure dropping a subscription for the same entity type still allows receiving of + // messages for other entity IDs of the same type. + let subscription3 = client + .subscribe_to_entity(3) + .unwrap() + .set_model(&model3, &mut cx.to_async()); + drop(subscription3); -// let user_id = 5; -// let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); -// let server = FakeServer::for_client(user_id, &client, cx).await; + server.send(proto::JoinProject { project_id: 1 }); + server.send(proto::JoinProject { project_id: 2 }); + done_rx1.next().await.unwrap(); + done_rx2.next().await.unwrap(); + } -// let (done_tx1, mut done_rx1) = smol::channel::unbounded(); -// let (done_tx2, mut done_rx2) = smol::channel::unbounded(); -// client.add_model_message_handler( -// move |model: ModelHandle, _: TypedEnvelope, _, cx| { -// match model.read_with(&cx, |model, _| model.id) { -// 1 => done_tx1.try_send(()).unwrap(), -// 2 => done_tx2.try_send(()).unwrap(), -// _ => unreachable!(), -// } -// async { Ok(()) } -// }, -// ); -// let model1 = cx.add_model(|_| Model { -// id: 1, -// subscription: None, -// }); -// let model2 = cx.add_model(|_| Model { -// id: 2, -// subscription: None, -// }); -// let model3 = cx.add_model(|_| Model { -// id: 3, -// subscription: None, -// }); + #[gpui2::test] + async fn test_subscribing_after_dropping_subscription(cx: &mut TestAppContext) { + let user_id = 5; + let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); + let server = FakeServer::for_client(user_id, &client, cx).await; -// let _subscription1 = client -// .subscribe_to_entity(1) -// .unwrap() -// .set_model(&model1, &mut cx.to_async()); -// let _subscription2 = client -// .subscribe_to_entity(2) -// .unwrap() -// .set_model(&model2, &mut cx.to_async()); -// // Ensure dropping a subscription for the same entity type still allows receiving of -// // messages for other entity IDs of the same type. -// let subscription3 = client -// .subscribe_to_entity(3) -// .unwrap() -// .set_model(&model3, &mut cx.to_async()); -// drop(subscription3); + let model = cx.entity(|_| Model::default()); + let (done_tx1, _done_rx1) = smol::channel::unbounded(); + let (done_tx2, mut done_rx2) = smol::channel::unbounded(); + let subscription1 = client.add_message_handler( + model.downgrade(), + move |_, _: TypedEnvelope, _, _| { + done_tx1.try_send(()).unwrap(); + async { Ok(()) } + }, + ); + drop(subscription1); + let _subscription2 = client.add_message_handler( + model.downgrade(), + move |_, _: TypedEnvelope, _, _| { + done_tx2.try_send(()).unwrap(); + async { Ok(()) } + }, + ); + server.send(proto::Ping {}); + done_rx2.next().await.unwrap(); + } -// server.send(proto::JoinProject { project_id: 1 }); -// server.send(proto::JoinProject { project_id: 2 }); -// done_rx1.next().await.unwrap(); -// done_rx2.next().await.unwrap(); -// } + #[gpui2::test] + async fn test_dropping_subscription_in_handler(cx: &mut TestAppContext) { + let user_id = 5; + let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); + let server = FakeServer::for_client(user_id, &client, cx).await; -// #[gpui::test] -// async fn test_subscribing_after_dropping_subscription(cx: &mut TestAppContext) { -// cx.foreground().forbid_parking(); + let model = cx.entity(|_| Model::default()); + let (done_tx, mut done_rx) = smol::channel::unbounded(); + let subscription = client.add_message_handler( + model.clone().downgrade(), + move |model: Handle, _: TypedEnvelope, _, mut cx| { + model + .update(&mut cx, |model, _| model.subscription.take()) + .unwrap(); + done_tx.try_send(()).unwrap(); + async { Ok(()) } + }, + ); + model.update(cx, |model, _| { + model.subscription = Some(subscription); + }); + server.send(proto::Ping {}); + done_rx.next().await.unwrap(); + } -// let user_id = 5; -// let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); -// let server = FakeServer::for_client(user_id, &client, cx).await; - -// let model = cx.add_model(|_| Model::default()); -// let (done_tx1, _done_rx1) = smol::channel::unbounded(); -// let (done_tx2, mut done_rx2) = smol::channel::unbounded(); -// let subscription1 = client.add_message_handler( -// model.clone(), -// move |_, _: TypedEnvelope, _, _| { -// done_tx1.try_send(()).unwrap(); -// async { Ok(()) } -// }, -// ); -// drop(subscription1); -// let _subscription2 = client.add_message_handler( -// model.clone(), -// move |_, _: TypedEnvelope, _, _| { -// done_tx2.try_send(()).unwrap(); -// async { Ok(()) } -// }, -// ); -// server.send(proto::Ping {}); -// done_rx2.next().await.unwrap(); -// } - -// #[gpui::test] -// async fn test_dropping_subscription_in_handler(cx: &mut TestAppContext) { -// cx.foreground().forbid_parking(); - -// let user_id = 5; -// let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); -// let server = FakeServer::for_client(user_id, &client, cx).await; - -// let model = cx.add_model(|_| Model::default()); -// let (done_tx, mut done_rx) = smol::channel::unbounded(); -// let subscription = client.add_message_handler( -// model.clone(), -// move |model, _: TypedEnvelope, _, mut cx| { -// model.update(&mut cx, |model, _| model.subscription.take()); -// done_tx.try_send(()).unwrap(); -// async { Ok(()) } -// }, -// ); -// model.update(cx, |model, _| { -// model.subscription = Some(subscription); -// }); -// server.send(proto::Ping {}); -// done_rx.next().await.unwrap(); -// } - -// #[derive(Default)] -// struct Model { -// id: usize, -// subscription: Option, -// } - -// impl Entity for Model { -// type Event = (); -// } -// } + #[derive(Default)] + struct Model { + id: usize, + subscription: Option, + } +} diff --git a/crates/client2/src/test.rs b/crates/client2/src/test.rs index 96c20791ec..1b32d35092 100644 --- a/crates/client2/src/test.rs +++ b/crates/client2/src/test.rs @@ -1,215 +1,216 @@ -// use crate::{Client, Connection, Credentials, EstablishConnectionError, UserStore}; -// use anyhow::{anyhow, Result}; -// use futures::{stream::BoxStream, StreamExt}; -// use gpui2::{Executor, Handle, TestAppContext}; -// use parking_lot::Mutex; -// use rpc::{ -// proto::{self, GetPrivateUserInfo, GetPrivateUserInfoResponse}, -// ConnectionId, Peer, Receipt, TypedEnvelope, -// }; -// use std::{rc::Rc, sync::Arc}; -// use util::http::FakeHttpClient; +use crate::{Client, Connection, Credentials, EstablishConnectionError, UserStore}; +use anyhow::{anyhow, Result}; +use futures::{stream::BoxStream, StreamExt}; +use gpui2::{Context, Executor, Handle, TestAppContext}; +use parking_lot::Mutex; +use rpc2::{ + proto::{self, GetPrivateUserInfo, GetPrivateUserInfoResponse}, + ConnectionId, Peer, Receipt, TypedEnvelope, +}; +use std::sync::Arc; +use util::http::FakeHttpClient; -// pub struct FakeServer { -// peer: Arc, -// state: Arc>, -// user_id: u64, -// executor: Executor, -// } +pub struct FakeServer { + peer: Arc, + state: Arc>, + user_id: u64, + executor: Executor, +} -// #[derive(Default)] -// struct FakeServerState { -// incoming: Option>>, -// connection_id: Option, -// forbid_connections: bool, -// auth_count: usize, -// access_token: usize, -// } +#[derive(Default)] +struct FakeServerState { + incoming: Option>>, + connection_id: Option, + forbid_connections: bool, + auth_count: usize, + access_token: usize, +} -// impl FakeServer { -// pub async fn for_client( -// client_user_id: u64, -// client: &Arc, -// cx: &TestAppContext, -// ) -> Self { -// let server = Self { -// peer: Peer::new(0), -// state: Default::default(), -// user_id: client_user_id, -// executor: cx.foreground(), -// }; +impl FakeServer { + pub async fn for_client( + client_user_id: u64, + client: &Arc, + cx: &TestAppContext, + ) -> Self { + let server = Self { + peer: Peer::new(0), + state: Default::default(), + user_id: client_user_id, + executor: cx.executor().clone(), + }; -// client -// .override_authenticate({ -// let state = Arc::downgrade(&server.state); -// move |cx| { -// let state = state.clone(); -// cx.spawn(move |_| async move { -// let state = state.upgrade().ok_or_else(|| anyhow!("server dropped"))?; -// let mut state = state.lock(); -// state.auth_count += 1; -// let access_token = state.access_token.to_string(); -// Ok(Credentials { -// user_id: client_user_id, -// access_token, -// }) -// }) -// } -// }) -// .override_establish_connection({ -// let peer = Arc::downgrade(&server.peer); -// let state = Arc::downgrade(&server.state); -// move |credentials, cx| { -// let peer = peer.clone(); -// let state = state.clone(); -// let credentials = credentials.clone(); -// cx.spawn(move |cx| async move { -// let state = state.upgrade().ok_or_else(|| anyhow!("server dropped"))?; -// let peer = peer.upgrade().ok_or_else(|| anyhow!("server dropped"))?; -// if state.lock().forbid_connections { -// Err(EstablishConnectionError::Other(anyhow!( -// "server is forbidding connections" -// )))? -// } + client + .override_authenticate({ + let state = Arc::downgrade(&server.state); + move |cx| { + let state = state.clone(); + cx.spawn(move |_| async move { + let state = state.upgrade().ok_or_else(|| anyhow!("server dropped"))?; + let mut state = state.lock(); + state.auth_count += 1; + let access_token = state.access_token.to_string(); + Ok(Credentials { + user_id: client_user_id, + access_token, + }) + }) + } + }) + .override_establish_connection({ + let peer = Arc::downgrade(&server.peer); + let state = Arc::downgrade(&server.state); + move |credentials, cx| { + let peer = peer.clone(); + let state = state.clone(); + let credentials = credentials.clone(); + cx.spawn(move |cx| async move { + let state = state.upgrade().ok_or_else(|| anyhow!("server dropped"))?; + let peer = peer.upgrade().ok_or_else(|| anyhow!("server dropped"))?; + if state.lock().forbid_connections { + Err(EstablishConnectionError::Other(anyhow!( + "server is forbidding connections" + )))? + } -// assert_eq!(credentials.user_id, client_user_id); + assert_eq!(credentials.user_id, client_user_id); -// if credentials.access_token != state.lock().access_token.to_string() { -// Err(EstablishConnectionError::Unauthorized)? -// } + if credentials.access_token != state.lock().access_token.to_string() { + Err(EstablishConnectionError::Unauthorized)? + } -// let (client_conn, server_conn, _) = Connection::in_memory(cx.background()); -// let (connection_id, io, incoming) = -// peer.add_test_connection(server_conn, cx.background()); -// cx.background().spawn(io).detach(); -// { -// let mut state = state.lock(); -// state.connection_id = Some(connection_id); -// state.incoming = Some(incoming); -// } -// peer.send( -// connection_id, -// proto::Hello { -// peer_id: Some(connection_id.into()), -// }, -// ) -// .unwrap(); + let (client_conn, server_conn, _) = + Connection::in_memory(cx.executor().clone()); + let (connection_id, io, incoming) = + peer.add_test_connection(server_conn, cx.executor().clone()); + cx.executor().spawn(io).detach(); + { + let mut state = state.lock(); + state.connection_id = Some(connection_id); + state.incoming = Some(incoming); + } + peer.send( + connection_id, + proto::Hello { + peer_id: Some(connection_id.into()), + }, + ) + .unwrap(); -// Ok(client_conn) -// }) -// } -// }); + Ok(client_conn) + }) + } + }); -// client -// .authenticate_and_connect(false, &cx.to_async()) -// .await -// .unwrap(); + client + .authenticate_and_connect(false, &cx.to_async()) + .await + .unwrap(); -// server -// } + server + } -// pub fn disconnect(&self) { -// if self.state.lock().connection_id.is_some() { -// self.peer.disconnect(self.connection_id()); -// let mut state = self.state.lock(); -// state.connection_id.take(); -// state.incoming.take(); -// } -// } + pub fn disconnect(&self) { + if self.state.lock().connection_id.is_some() { + self.peer.disconnect(self.connection_id()); + let mut state = self.state.lock(); + state.connection_id.take(); + state.incoming.take(); + } + } -// pub fn auth_count(&self) -> usize { -// self.state.lock().auth_count -// } + pub fn auth_count(&self) -> usize { + self.state.lock().auth_count + } -// pub fn roll_access_token(&self) { -// self.state.lock().access_token += 1; -// } + pub fn roll_access_token(&self) { + self.state.lock().access_token += 1; + } -// pub fn forbid_connections(&self) { -// self.state.lock().forbid_connections = true; -// } + pub fn forbid_connections(&self) { + self.state.lock().forbid_connections = true; + } -// pub fn allow_connections(&self) { -// self.state.lock().forbid_connections = false; -// } + pub fn allow_connections(&self) { + self.state.lock().forbid_connections = false; + } -// pub fn send(&self, message: T) { -// self.peer.send(self.connection_id(), message).unwrap(); -// } + pub fn send(&self, message: T) { + self.peer.send(self.connection_id(), message).unwrap(); + } -// #[allow(clippy::await_holding_lock)] -// pub async fn receive(&self) -> Result> { -// self.executor.start_waiting(); + #[allow(clippy::await_holding_lock)] + pub async fn receive(&self) -> Result> { + self.executor.start_waiting(); -// loop { -// let message = self -// .state -// .lock() -// .incoming -// .as_mut() -// .expect("not connected") -// .next() -// .await -// .ok_or_else(|| anyhow!("other half hung up"))?; -// self.executor.finish_waiting(); -// let type_name = message.payload_type_name(); -// let message = message.into_any(); + loop { + let message = self + .state + .lock() + .incoming + .as_mut() + .expect("not connected") + .next() + .await + .ok_or_else(|| anyhow!("other half hung up"))?; + self.executor.finish_waiting(); + let type_name = message.payload_type_name(); + let message = message.into_any(); -// if message.is::>() { -// return Ok(*message.downcast().unwrap()); -// } + if message.is::>() { + return Ok(*message.downcast().unwrap()); + } -// if message.is::>() { -// self.respond( -// message -// .downcast::>() -// .unwrap() -// .receipt(), -// GetPrivateUserInfoResponse { -// metrics_id: "the-metrics-id".into(), -// staff: false, -// flags: Default::default(), -// }, -// ); -// continue; -// } + if message.is::>() { + self.respond( + message + .downcast::>() + .unwrap() + .receipt(), + GetPrivateUserInfoResponse { + metrics_id: "the-metrics-id".into(), + staff: false, + flags: Default::default(), + }, + ); + continue; + } -// panic!( -// "fake server received unexpected message type: {:?}", -// type_name -// ); -// } -// } + panic!( + "fake server received unexpected message type: {:?}", + type_name + ); + } + } -// pub fn respond(&self, receipt: Receipt, response: T::Response) { -// self.peer.respond(receipt, response).unwrap() -// } + pub fn respond(&self, receipt: Receipt, response: T::Response) { + self.peer.respond(receipt, response).unwrap() + } -// fn connection_id(&self) -> ConnectionId { -// self.state.lock().connection_id.expect("not connected") -// } + fn connection_id(&self) -> ConnectionId { + self.state.lock().connection_id.expect("not connected") + } -// pub async fn build_user_store( -// &self, -// client: Arc, -// cx: &mut TestAppContext, -// ) -> ModelHandle { -// let http_client = FakeHttpClient::with_404_response(); -// let user_store = cx.add_model(|cx| UserStore::new(client, http_client, cx)); -// assert_eq!( -// self.receive::() -// .await -// .unwrap() -// .payload -// .user_ids, -// &[self.user_id] -// ); -// user_store -// } -// } + pub async fn build_user_store( + &self, + client: Arc, + cx: &mut TestAppContext, + ) -> Handle { + let http_client = FakeHttpClient::with_404_response(); + let user_store = cx.entity(|cx| UserStore::new(client, http_client, cx)); + assert_eq!( + self.receive::() + .await + .unwrap() + .payload + .user_ids, + &[self.user_id] + ); + user_store + } +} -// impl Drop for FakeServer { -// fn drop(&mut self) { -// self.disconnect(); -// } -// } +impl Drop for FakeServer { + fn drop(&mut self) { + self.disconnect(); + } +} diff --git a/crates/gpui2/src/app/test_context.rs b/crates/gpui2/src/app/test_context.rs index 9133c31f52..274121b692 100644 --- a/crates/gpui2/src/app/test_context.rs +++ b/crates/gpui2/src/app/test_context.rs @@ -143,7 +143,7 @@ impl TestAppContext { lock.update_global(update) } - fn to_async(&self) -> AsyncAppContext { + pub fn to_async(&self) -> AsyncAppContext { AsyncAppContext { app: Arc::downgrade(&self.app), executor: self.executor.clone(), diff --git a/crates/gpui2/src/executor.rs b/crates/gpui2/src/executor.rs index 261912b085..28d4b6d117 100644 --- a/crates/gpui2/src/executor.rs +++ b/crates/gpui2/src/executor.rs @@ -146,7 +146,10 @@ impl Executor { Poll::Ready(result) => return result, Poll::Pending => { if !self.dispatcher.poll() { - // todo!("forbid_parking") + #[cfg(any(test, feature = "test-support"))] + if let Some(_) = self.dispatcher.as_test() { + panic!("blocked with nothing left to run") + } parker.park(); } } @@ -206,11 +209,26 @@ impl Executor { todo!("start_waiting") } + #[cfg(any(test, feature = "test-support"))] + pub fn finish_waiting(&self) { + todo!("finish_waiting") + } + #[cfg(any(test, feature = "test-support"))] pub fn simulate_random_delay(&self) -> impl Future { self.dispatcher.as_test().unwrap().simulate_random_delay() } + #[cfg(any(test, feature = "test-support"))] + pub fn advance_clock(&self, duration: Duration) { + self.dispatcher.as_test().unwrap().advance_clock(duration) + } + + #[cfg(any(test, feature = "test-support"))] + pub fn run_until_parked(&self) { + self.dispatcher.as_test().unwrap().run_until_parked() + } + pub fn num_cpus(&self) -> usize { num_cpus::get() } diff --git a/crates/gpui2/src/platform/test/dispatcher.rs b/crates/gpui2/src/platform/test/dispatcher.rs index 02873f8e6e..0ed5638a8b 100644 --- a/crates/gpui2/src/platform/test/dispatcher.rs +++ b/crates/gpui2/src/platform/test/dispatcher.rs @@ -8,7 +8,7 @@ use std::{ pin::Pin, sync::Arc, task::{Context, Poll}, - time::{Duration, Instant}, + time::Duration, }; use util::post_inc; @@ -24,8 +24,8 @@ struct TestDispatcherState { random: StdRng, foreground: HashMap>, background: Vec, - delayed: Vec<(Instant, Runnable)>, - time: Instant, + delayed: Vec<(Duration, Runnable)>, + time: Duration, is_main_thread: bool, next_id: TestDispatcherId, } @@ -37,7 +37,7 @@ impl TestDispatcher { foreground: HashMap::default(), background: Vec::new(), delayed: Vec::new(), - time: Instant::now(), + time: Duration::ZERO, is_main_thread: true, next_id: TestDispatcherId(1), }; @@ -49,7 +49,21 @@ impl TestDispatcher { } pub fn advance_clock(&self, by: Duration) { - self.state.lock().time += by; + let new_now = self.state.lock().time + by; + loop { + self.run_until_parked(); + let state = self.state.lock(); + let next_due_time = state.delayed.first().map(|(time, _)| *time); + drop(state); + if let Some(due_time) = next_due_time { + if due_time <= new_now { + self.state.lock().time = due_time; + continue; + } + } + break; + } + self.state.lock().time = new_now; } pub fn simulate_random_delay(&self) -> impl Future { @@ -137,10 +151,8 @@ impl PlatformDispatcher for TestDispatcher { let background_len = state.background.len(); if foreground_len == 0 && background_len == 0 { - eprintln!("no runnables to poll"); return false; } - eprintln!("runnables {} {}", foreground_len, background_len); let main_thread = state.random.gen_ratio( foreground_len as u32, @@ -150,7 +162,6 @@ impl PlatformDispatcher for TestDispatcher { state.is_main_thread = main_thread; let runnable = if main_thread { - eprintln!("running next main thread"); let state = &mut *state; let runnables = state .foreground @@ -161,7 +172,6 @@ impl PlatformDispatcher for TestDispatcher { runnables.pop_front().unwrap() } else { let ix = state.random.gen_range(0..background_len); - eprintln!("running background thread {ix}"); state.background.swap_remove(ix) }; diff --git a/crates/gpui2/src/platform/test/platform.rs b/crates/gpui2/src/platform/test/platform.rs index 9cc7d959e0..4d86c434d0 100644 --- a/crates/gpui2/src/platform/test/platform.rs +++ b/crates/gpui2/src/platform/test/platform.rs @@ -173,14 +173,14 @@ impl Platform for TestPlatform { } fn write_credentials(&self, _url: &str, _username: &str, _password: &[u8]) -> Result<()> { - unimplemented!() + Ok(()) } fn read_credentials(&self, _url: &str) -> Result)>> { - unimplemented!() + Ok(None) } fn delete_credentials(&self, _url: &str) -> Result<()> { - unimplemented!() + Ok(()) } } From 6fe393db2a3647ab49759a9dcba92c258ae76265 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 26 Oct 2023 14:48:04 +0200 Subject: [PATCH 21/24] Fix compile errors with lsp2 Co-authored-by: Jospeh --- crates/lsp2/src/lsp2.rs | 2 +- crates/project2/src/project2.rs | 2 +- crates/zed2/src/main.rs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/lsp2/src/lsp2.rs b/crates/lsp2/src/lsp2.rs index a6a9a4f639..27b7b36e73 100644 --- a/crates/lsp2/src/lsp2.rs +++ b/crates/lsp2/src/lsp2.rs @@ -240,7 +240,7 @@ impl LanguageServer { let stderr_input_task = stderr .map(|stderr| { let io_handlers = io_handlers.clone(); - let stderr_captures = stderr_captures.clone(); + let stderr_captures = stderr_capture.clone(); cx.spawn(|_| Self::handle_stderr(stderr, io_handlers, stderr_captures).log_err()) }) .unwrap_or_else(|| Task::Ready(Some(None))); diff --git a/crates/project2/src/project2.rs b/crates/project2/src/project2.rs index 4e52992380..b0fde1c486 100644 --- a/crates/project2/src/project2.rs +++ b/crates/project2/src/project2.rs @@ -2964,7 +2964,7 @@ impl Project { ) })??; - Ok(language_server) + Ok(Some(language_server)) } async fn setup_pending_language_server( diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index 69aecccd45..44a441db0b 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -117,7 +117,6 @@ fn main() { let copilot_language_server_id = languages.next_language_server_id(); languages.set_executor(cx.executor().clone()); languages.set_language_server_download_dir(paths::LANGUAGES_DIR.clone()); - let languages = Arc::new(languages); let node_runtime = RealNodeRuntime::new(http.clone()); language2::init(cx); From 88ef74ec8f1ac1544e4b97544132df4d87f1f0d8 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 26 Oct 2023 15:20:38 +0200 Subject: [PATCH 22/24] Checkpoint: Compiling after view type removal --- crates/gpui2_macros/src/derive_component.rs | 2 +- crates/storybook2/src/stories/z_index.rs | 27 ++---- crates/ui2/src/components/assistant_panel.rs | 14 +-- crates/ui2/src/components/breadcrumb.rs | 26 ++---- crates/ui2/src/components/buffer.rs | 28 ++---- crates/ui2/src/components/chat_panel.rs | 34 +++---- crates/ui2/src/components/collab_panel.rs | 27 ++---- crates/ui2/src/components/command_palette.rs | 28 ++---- crates/ui2/src/components/context_menu.rs | 36 +++----- crates/ui2/src/components/copilot.rs | 28 ++---- crates/ui2/src/components/editor_pane.rs | 8 +- crates/ui2/src/components/facepile.rs | 24 ++--- crates/ui2/src/components/icon_button.rs | 16 +--- crates/ui2/src/components/keybinding.rs | 37 +++----- .../ui2/src/components/language_selector.rs | 28 ++---- crates/ui2/src/components/list.rs | 91 +++++++++---------- crates/ui2/src/components/modal.rs | 10 +- crates/ui2/src/components/multi_buffer.rs | 32 +++---- .../ui2/src/components/notification_toast.rs | 10 +- .../ui2/src/components/notifications_panel.rs | 23 ++--- crates/ui2/src/components/palette.rs | 38 +++----- crates/ui2/src/components/panel.rs | 22 ++--- crates/ui2/src/components/panes.rs | 9 +- crates/ui2/src/components/player_stack.rs | 10 +- crates/ui2/src/components/project_panel.rs | 28 ++---- crates/ui2/src/components/recent_projects.rs | 28 ++---- crates/ui2/src/components/tab.rs | 24 ++--- crates/ui2/src/components/tab_bar.rs | 28 ++---- crates/ui2/src/components/terminal.rs | 28 ++---- crates/ui2/src/components/theme_selector.rs | 28 ++---- crates/ui2/src/components/toast.rs | 20 ++-- crates/ui2/src/components/toolbar.rs | 19 ++-- crates/ui2/src/components/traffic_lights.rs | 32 +++---- crates/ui2/src/element_ext.rs | 4 +- crates/ui2/src/elements/avatar.rs | 24 ++--- crates/ui2/src/elements/button.rs | 50 +++++----- crates/ui2/src/elements/details.rs | 24 ++--- crates/ui2/src/elements/icon.rs | 24 ++--- crates/ui2/src/elements/input.rs | 24 ++--- crates/ui2/src/elements/label.rs | 32 +++---- crates/ui2/src/elements/stack.rs | 6 +- crates/ui2/src/elements/tool_divider.rs | 14 +-- crates/ui2/src/static_data.rs | 34 +++---- crates/ui2/src/story.rs | 8 +- 44 files changed, 392 insertions(+), 695 deletions(-) diff --git a/crates/gpui2_macros/src/derive_component.rs b/crates/gpui2_macros/src/derive_component.rs index 97cfac1ae5..f30ff3748f 100644 --- a/crates/gpui2_macros/src/derive_component.rs +++ b/crates/gpui2_macros/src/derive_component.rs @@ -19,7 +19,7 @@ pub fn derive_component(input: TokenStream) -> TokenStream { }) { quote! { #first_type_param } } else { - trait_generics.params.push(parse_quote! { V: 'static + Send + Sync }); + trait_generics.params.push(parse_quote! { V: 'static }); quote! { V } } }; diff --git a/crates/storybook2/src/stories/z_index.rs b/crates/storybook2/src/stories/z_index.rs index d68b4916c2..7fa078c4e3 100644 --- a/crates/storybook2/src/stories/z_index.rs +++ b/crates/storybook2/src/stories/z_index.rs @@ -1,4 +1,3 @@ -use std::marker::PhantomData; use gpui2::{px, rgb, Div, Hsla}; use ui::prelude::*; @@ -8,18 +7,14 @@ use crate::story::Story; /// A reimplementation of the MDN `z-index` example, found here: /// [https://developer.mozilla.org/en-US/docs/Web/CSS/z-index](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index). #[derive(Component)] -pub struct ZIndexStory { - state_type: PhantomData, -} +pub struct ZIndexStory; -impl ZIndexStory { +impl ZIndexStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) .child(Story::title(cx, "z-index")) .child( @@ -86,23 +81,19 @@ trait Styles: Styled + Sized { } } -impl Styles for Div {} +impl Styles for Div {} #[derive(Component)] -struct ZIndexExample { - view_type: PhantomData, +struct ZIndexExample { z_index: u32, } -impl ZIndexExample { +impl ZIndexExample { pub fn new(z_index: u32) -> Self { - Self { - view_type: PhantomData, - z_index, - } + Self { z_index } } - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { div() .relative() .size_full() diff --git a/crates/ui2/src/components/assistant_panel.rs b/crates/ui2/src/components/assistant_panel.rs index 25f24f1483..defd05f500 100644 --- a/crates/ui2/src/components/assistant_panel.rs +++ b/crates/ui2/src/components/assistant_panel.rs @@ -1,22 +1,18 @@ -use std::marker::PhantomData; - use gpui2::{rems, AbsoluteLength}; use crate::prelude::*; use crate::{Icon, IconButton, Label, Panel, PanelSide}; #[derive(Component)] -pub struct AssistantPanel { +pub struct AssistantPanel { id: ElementId, - state_type: PhantomData, current_side: PanelSide, } -impl AssistantPanel { +impl AssistantPanel { pub fn new(id: impl Into) -> Self { Self { id: id.into(), - state_type: PhantomData, current_side: PanelSide::default(), } } @@ -26,7 +22,7 @@ impl AssistantPanel { self } - fn render(self, view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, view: &mut V, cx: &mut ViewContext) -> impl Component { Panel::new(self.id.clone(), cx) .children(vec![div() .flex() @@ -92,9 +88,9 @@ mod stories { Self {} } - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, AssistantPanel>(cx)) + .child(Story::title_for::<_, AssistantPanel>(cx)) .child(Story::label(cx, "Default")) .child(AssistantPanel::new("assistant-panel")) } diff --git a/crates/ui2/src/components/breadcrumb.rs b/crates/ui2/src/components/breadcrumb.rs index 289c071021..3cba3b7248 100644 --- a/crates/ui2/src/components/breadcrumb.rs +++ b/crates/ui2/src/components/breadcrumb.rs @@ -1,8 +1,6 @@ -use std::marker::PhantomData; use std::path::PathBuf; use gpui2::Div; - use crate::prelude::*; use crate::{h_stack, HighlightedText}; @@ -10,28 +8,26 @@ use crate::{h_stack, HighlightedText}; pub struct Symbol(pub Vec); #[derive(Component)] -pub struct Breadcrumb { - state_type: PhantomData, +pub struct Breadcrumb { path: PathBuf, symbols: Vec, } -impl Breadcrumb { +impl Breadcrumb { pub fn new(path: PathBuf, symbols: Vec) -> Self { Self { - state_type: PhantomData, path, symbols, } } - fn render_separator(&self, cx: &WindowContext) -> Div { + fn render_separator(&self, cx: &WindowContext) -> Div { let theme = theme(cx); div().child(" › ").text_color(theme.text_muted) } - fn render(self, view_state: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, view_state: &mut V, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let symbols_len = self.symbols.len(); @@ -87,22 +83,18 @@ mod stories { use super::*; #[derive(Component)] - pub struct BreadcrumbStory { - state_type: PhantomData, - } + pub struct BreadcrumbStory; - impl BreadcrumbStory { + impl BreadcrumbStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, view_state: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, view_state: &mut V, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); Story::container(cx) - .child(Story::title_for::<_, Breadcrumb>(cx)) + .child(Story::title_for::<_, Breadcrumb>(cx)) .child(Story::label(cx, "Default")) .child(Breadcrumb::new( PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(), diff --git a/crates/ui2/src/components/buffer.rs b/crates/ui2/src/components/buffer.rs index ffef5c4039..b4ccb89b5c 100644 --- a/crates/ui2/src/components/buffer.rs +++ b/crates/ui2/src/components/buffer.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use gpui2::{Hsla, WindowContext}; use crate::prelude::*; @@ -110,9 +108,8 @@ impl BufferRow { } #[derive(Component, Clone)] -pub struct Buffer { +pub struct Buffer { id: ElementId, - state_type: PhantomData, rows: Option, readonly: bool, language: Option, @@ -120,11 +117,10 @@ pub struct Buffer { path: Option, } -impl Buffer { +impl Buffer { pub fn new(id: impl Into) -> Self { Self { id: id.into(), - state_type: PhantomData, rows: Some(BufferRows::default()), readonly: false, language: None, @@ -158,7 +154,7 @@ impl Buffer { self } - fn render_row(row: BufferRow, cx: &WindowContext) -> impl Component { + fn render_row(row: BufferRow, cx: &WindowContext) -> impl Component { let theme = theme(cx); let line_background = if row.current { @@ -208,7 +204,7 @@ impl Buffer { })) } - fn render_rows(&self, cx: &WindowContext) -> Vec> { + fn render_rows(&self, cx: &WindowContext) -> Vec> { match &self.rows { Some(rows) => rows .rows @@ -219,7 +215,7 @@ impl Buffer { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let rows = self.render_rows(cx); @@ -247,22 +243,18 @@ mod stories { use super::*; #[derive(Component)] - pub struct BufferStory { - state_type: PhantomData, - } + pub struct BufferStory; - impl BufferStory { + impl BufferStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); Story::container(cx) - .child(Story::title_for::<_, Buffer>(cx)) + .child(Story::title_for::<_, Buffer>(cx)) .child(Story::label(cx, "Default")) .child(div().w(rems(64.)).h_96().child(empty_buffer_example())) .child(Story::label(cx, "Hello World (Rust)")) diff --git a/crates/ui2/src/components/chat_panel.rs b/crates/ui2/src/components/chat_panel.rs index 2800207b34..e4494f4614 100644 --- a/crates/ui2/src/components/chat_panel.rs +++ b/crates/ui2/src/components/chat_panel.rs @@ -1,17 +1,15 @@ -use std::marker::PhantomData; - use chrono::NaiveDateTime; use crate::prelude::*; use crate::{Icon, IconButton, Input, Label, LabelColor}; #[derive(Component)] -pub struct ChatPanel { +pub struct ChatPanel { element_id: ElementId, - messages: Vec>, + messages: Vec, } -impl ChatPanel { +impl ChatPanel { pub fn new(element_id: impl Into) -> Self { Self { element_id: element_id.into(), @@ -19,12 +17,12 @@ impl ChatPanel { } } - pub fn messages(mut self, messages: Vec>) -> Self { + pub fn messages(mut self, messages: Vec) -> Self { self.messages = messages; self } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .id(self.element_id.clone()) .flex() @@ -71,24 +69,22 @@ impl ChatPanel { } #[derive(Component)] -pub struct ChatMessage { - state_type: PhantomData, +pub struct ChatMessage { author: String, text: String, sent_at: NaiveDateTime, } -impl ChatMessage { +impl ChatMessage { pub fn new(author: String, text: String, sent_at: NaiveDateTime) -> Self { Self { - state_type: PhantomData, author, text, sent_at, } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .flex() .flex_col() @@ -118,20 +114,16 @@ mod stories { use super::*; #[derive(Component)] - pub struct ChatPanelStory { - state_type: PhantomData, - } + pub struct ChatPanelStory; - impl ChatPanelStory { + impl ChatPanelStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, ChatPanel>(cx)) + .child(Story::title_for::<_, ChatPanel>(cx)) .child(Story::label(cx, "Default")) .child( Panel::new("chat-panel-1-outer", cx) diff --git a/crates/ui2/src/components/collab_panel.rs b/crates/ui2/src/components/collab_panel.rs index 8f30b33da0..6d2cbd8e14 100644 --- a/crates/ui2/src/components/collab_panel.rs +++ b/crates/ui2/src/components/collab_panel.rs @@ -3,23 +3,18 @@ use crate::{ static_collab_panel_channels, static_collab_panel_current_call, v_stack, Icon, List, ListHeader, ToggleState, }; -use std::marker::PhantomData; #[derive(Component)] -pub struct CollabPanel { +pub struct CollabPanel { id: ElementId, - state_type: PhantomData, } -impl CollabPanel { +impl CollabPanel { pub fn new(id: impl Into) -> Self { - Self { - id: id.into(), - state_type: PhantomData, - } + Self { id: id.into() } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); v_stack() @@ -99,20 +94,16 @@ mod stories { use super::*; #[derive(Component)] - pub struct CollabPanelStory { - state_type: PhantomData, - } + pub struct CollabPanelStory; - impl CollabPanelStory { + impl CollabPanelStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, CollabPanel>(cx)) + .child(Story::title_for::<_, CollabPanel>(cx)) .child(Story::label(cx, "Default")) .child(CollabPanel::new("collab-panel")) } diff --git a/crates/ui2/src/components/command_palette.rs b/crates/ui2/src/components/command_palette.rs index d00b9b7743..065ee9a052 100644 --- a/crates/ui2/src/components/command_palette.rs +++ b/crates/ui2/src/components/command_palette.rs @@ -1,23 +1,17 @@ -use std::marker::PhantomData; - use crate::prelude::*; use crate::{example_editor_actions, OrderMethod, Palette}; #[derive(Component)] -pub struct CommandPalette { +pub struct CommandPalette { id: ElementId, - state_type: PhantomData, } -impl CommandPalette { +impl CommandPalette { pub fn new(id: impl Into) -> Self { - Self { - id: id.into(), - state_type: PhantomData, - } + Self { id: id.into() } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().id(self.id.clone()).child( Palette::new("palette") .items(example_editor_actions()) @@ -38,20 +32,16 @@ mod stories { use super::*; #[derive(Component)] - pub struct CommandPaletteStory { - state_type: PhantomData, - } + pub struct CommandPaletteStory; - impl CommandPaletteStory { + impl CommandPaletteStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, CommandPalette>(cx)) + .child(Story::title_for::<_, CommandPalette>(cx)) .child(Story::label(cx, "Default")) .child(CommandPalette::new("command-palette")) } diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index b52051daa3..3e0323d942 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -1,14 +1,14 @@ use crate::{prelude::*, ListItemVariant}; use crate::{v_stack, Label, List, ListEntry, ListItem, ListSeparator, ListSubHeader}; -pub enum ContextMenuItem { +pub enum ContextMenuItem { Header(SharedString), - Entry(Label), + Entry(Label), Separator, } -impl ContextMenuItem { - fn to_list_item(self) -> ListItem { +impl ContextMenuItem { + fn to_list_item(self) -> ListItem { match self { ContextMenuItem::Header(label) => ListSubHeader::new(label).into(), ContextMenuItem::Entry(label) => { @@ -26,23 +26,23 @@ impl ContextMenuItem { Self::Separator } - pub fn entry(label: Label) -> Self { + pub fn entry(label: Label) -> Self { Self::Entry(label) } } #[derive(Component)] -pub struct ContextMenu { - items: Vec>, +pub struct ContextMenu { + items: Vec, } -impl ContextMenu { - pub fn new(items: impl IntoIterator>) -> Self { +impl ContextMenu { + pub fn new(items: impl IntoIterator) -> Self { Self { items: items.into_iter().collect(), } } - fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(mut self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); v_stack() @@ -67,27 +67,21 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use std::marker::PhantomData; - use crate::story::Story; use super::*; #[derive(Component)] - pub struct ContextMenuStory { - state_type: PhantomData, - } + pub struct ContextMenuStory; - impl ContextMenuStory { + impl ContextMenuStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, ContextMenu>(cx)) + .child(Story::title_for::<_, ContextMenu>(cx)) .child(Story::label(cx, "Default")) .child(ContextMenu::new([ ContextMenuItem::header("Section header"), diff --git a/crates/ui2/src/components/copilot.rs b/crates/ui2/src/components/copilot.rs index 9e5454ee8a..3c48ef20d0 100644 --- a/crates/ui2/src/components/copilot.rs +++ b/crates/ui2/src/components/copilot.rs @@ -1,22 +1,16 @@ -use std::marker::PhantomData; - use crate::{prelude::*, Button, Label, LabelColor, Modal}; #[derive(Component)] -pub struct CopilotModal { +pub struct CopilotModal { id: ElementId, - state_type: PhantomData, } -impl CopilotModal { +impl CopilotModal { pub fn new(id: impl Into) -> Self { - Self { - id: id.into(), - state_type: PhantomData, - } + Self { id: id.into() } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().id(self.id.clone()).child( Modal::new("some-id") .title("Connect Copilot to Zed") @@ -36,20 +30,16 @@ mod stories { use super::*; #[derive(Component)] - pub struct CopilotModalStory { - state_type: PhantomData, - } + pub struct CopilotModalStory; - impl CopilotModalStory { + impl CopilotModalStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, CopilotModal>(cx)) + .child(Story::title_for::<_, CopilotModal>(cx)) .child(Story::label(cx, "Default")) .child(CopilotModal::new("copilot-modal")) } diff --git a/crates/ui2/src/components/editor_pane.rs b/crates/ui2/src/components/editor_pane.rs index fb26dad791..9c9638d057 100644 --- a/crates/ui2/src/components/editor_pane.rs +++ b/crates/ui2/src/components/editor_pane.rs @@ -10,10 +10,10 @@ use crate::{ #[derive(Clone)] pub struct EditorPane { - tabs: Vec>, + tabs: Vec, path: PathBuf, symbols: Vec, - buffer: Buffer, + buffer: Buffer, buffer_search: View, is_buffer_search_open: bool, } @@ -21,10 +21,10 @@ pub struct EditorPane { impl EditorPane { pub fn new( cx: &mut WindowContext, - tabs: Vec>, + tabs: Vec, path: PathBuf, symbols: Vec, - buffer: Buffer, + buffer: Buffer, ) -> Self { Self { tabs, diff --git a/crates/ui2/src/components/facepile.rs b/crates/ui2/src/components/facepile.rs index 565396e733..898489f1ed 100644 --- a/crates/ui2/src/components/facepile.rs +++ b/crates/ui2/src/components/facepile.rs @@ -1,23 +1,19 @@ -use std::marker::PhantomData; - use crate::prelude::*; use crate::{Avatar, Player}; #[derive(Component)] -pub struct Facepile { - state_type: PhantomData, +pub struct Facepile { players: Vec, } -impl Facepile { +impl Facepile { pub fn new>(players: P) -> Self { Self { - state_type: PhantomData, players: players.collect(), } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let player_count = self.players.len(); let player_list = self.players.iter().enumerate().map(|(ix, player)| { let isnt_last = ix < player_count - 1; @@ -40,22 +36,18 @@ mod stories { use super::*; #[derive(Component)] - pub struct FacepileStory { - state_type: PhantomData, - } + pub struct FacepileStory; - impl FacepileStory { + impl FacepileStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let players = static_players(); Story::container(cx) - .child(Story::title_for::<_, Facepile>(cx)) + .child(Story::title_for::<_, Facepile>(cx)) .child(Story::label(cx, "Default")) .child( div() diff --git a/crates/ui2/src/components/icon_button.rs b/crates/ui2/src/components/icon_button.rs index fe41de15a0..2891ce6bd8 100644 --- a/crates/ui2/src/components/icon_button.rs +++ b/crates/ui2/src/components/icon_button.rs @@ -1,4 +1,3 @@ -use std::marker::PhantomData; use std::sync::Arc; use gpui2::MouseButton; @@ -6,19 +5,18 @@ use gpui2::MouseButton; use crate::{h_stack, prelude::*}; use crate::{ClickHandler, Icon, IconColor, IconElement}; -struct IconButtonHandlers { +struct IconButtonHandlers { click: Option>, } -impl Default for IconButtonHandlers { +impl Default for IconButtonHandlers { fn default() -> Self { Self { click: None } } } #[derive(Component)] -pub struct IconButton { - state_type: PhantomData, +pub struct IconButton { id: ElementId, icon: Icon, color: IconColor, @@ -27,10 +25,9 @@ pub struct IconButton { handlers: IconButtonHandlers, } -impl IconButton { +impl IconButton { pub fn new(id: impl Into, icon: Icon) -> Self { Self { - state_type: PhantomData, id: id.into(), icon, color: IconColor::default(), @@ -60,10 +57,7 @@ impl IconButton { self } - pub fn on_click( - mut self, - handler: impl Fn(&mut S, &mut ViewContext) + 'static + Send + Sync, - ) -> Self { + pub fn on_click(mut self, handler: impl 'static + Fn(&mut S, &mut ViewContext) + Send + Sync) -> Self { self.handlers.click = Some(Arc::new(handler)); self } diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index d77798ad6c..2b0eefa4ea 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -1,14 +1,11 @@ use std::collections::HashSet; -use std::marker::PhantomData; use strum::{EnumIter, IntoEnumIterator}; use crate::prelude::*; #[derive(Component)] -pub struct Keybinding { - state_type: PhantomData, - +pub struct Keybinding { /// A keybinding consists of a key and a set of modifier keys. /// More then one keybinding produces a chord. /// @@ -16,10 +13,9 @@ pub struct Keybinding { keybinding: Vec<(String, ModifierKeys)>, } -impl Keybinding { +impl Keybinding { pub fn new(key: String, modifiers: ModifierKeys) -> Self { Self { - state_type: PhantomData, keybinding: vec![(key, modifiers)], } } @@ -29,12 +25,11 @@ impl Keybinding { second_note: (String, ModifierKeys), ) -> Self { Self { - state_type: PhantomData, keybinding: vec![first_note, second_note], } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div() .flex() .gap_2() @@ -55,20 +50,16 @@ impl Keybinding { } #[derive(Component)] -pub struct Key { - state_type: PhantomData, +pub struct Key { key: SharedString, } -impl Key { +impl Key { pub fn new(key: impl Into) -> Self { - Self { - state_type: PhantomData, - key: key.into(), - } + Self { key: key.into() } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); div() @@ -174,22 +165,18 @@ mod stories { use super::*; #[derive(Component)] - pub struct KeybindingStory { - state_type: PhantomData, - } + pub struct KeybindingStory; - impl KeybindingStory { + impl KeybindingStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { let all_modifier_permutations = ModifierKey::iter().permutations(2); Story::container(cx) - .child(Story::title_for::<_, Keybinding>(cx)) + .child(Story::title_for::<_, Keybinding>(cx)) .child(Story::label(cx, "Single Key")) .child(Keybinding::new("Z".to_string(), ModifierKeys::new())) .child(Story::label(cx, "Single Key with Modifier")) diff --git a/crates/ui2/src/components/language_selector.rs b/crates/ui2/src/components/language_selector.rs index ebb8f152f8..db42b28281 100644 --- a/crates/ui2/src/components/language_selector.rs +++ b/crates/ui2/src/components/language_selector.rs @@ -1,23 +1,17 @@ -use std::marker::PhantomData; - use crate::prelude::*; use crate::{OrderMethod, Palette, PaletteItem}; #[derive(Component)] -pub struct LanguageSelector { +pub struct LanguageSelector { id: ElementId, - state_type: PhantomData, } -impl LanguageSelector { +impl LanguageSelector { pub fn new(id: impl Into) -> Self { - Self { - id: id.into(), - state_type: PhantomData, - } + Self { id: id.into() } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { div().id(self.id.clone()).child( Palette::new("palette") .items(vec![ @@ -49,20 +43,16 @@ mod stories { use super::*; #[derive(Component)] - pub struct LanguageSelectorStory { - state_type: PhantomData, - } + pub struct LanguageSelectorStory; - impl LanguageSelectorStory { + impl LanguageSelectorStory { pub fn new() -> Self { - Self { - state_type: PhantomData, - } + Self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { Story::container(cx) - .child(Story::title_for::<_, LanguageSelector>(cx)) + .child(Story::title_for::<_, LanguageSelector>(cx)) .child(Story::label(cx, "Default")) .child(LanguageSelector::new("language-selector")) } diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index b1b3f506ea..0bf413e217 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use gpui2::{div, relative, Div}; use crate::settings::user_settings; @@ -18,8 +16,7 @@ pub enum ListItemVariant { } #[derive(Component)] -pub struct ListHeader { - state_type: PhantomData, +pub struct ListHeader { label: SharedString, left_icon: Option, variant: ListItemVariant, @@ -27,10 +24,9 @@ pub struct ListHeader { toggleable: Toggleable, } -impl ListHeader { +impl ListHeader { pub fn new(label: impl Into) -> Self { Self { - state_type: PhantomData, label: label.into(), left_icon: None, variant: ListItemVariant::default(), @@ -59,7 +55,7 @@ impl ListHeader { self } - fn disclosure_control(&self) -> Div { + fn disclosure_control(&self) -> Div { let is_toggleable = self.toggleable != Toggleable::NotToggleable; let is_toggled = Toggleable::is_toggled(&self.toggleable); @@ -92,7 +88,7 @@ impl ListHeader { } } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { let theme = theme(cx); let is_toggleable = self.toggleable != Toggleable::NotToggleable; @@ -135,17 +131,15 @@ impl ListHeader { } #[derive(Component)] -pub struct ListSubHeader { - state_type: PhantomData, +pub struct ListSubHeader { label: SharedString, left_icon: Option, variant: ListItemVariant, } -impl ListSubHeader { +impl ListSubHeader { pub fn new(label: impl Into) -> Self { Self { - state_type: PhantomData, label: label.into(), left_icon: None, variant: ListItemVariant::default(), @@ -157,7 +151,7 @@ impl ListSubHeader { self } - fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut S, cx: &mut ViewContext) -> impl Component { h_stack().flex_1().w_full().relative().py_1().child( div() .h_6() @@ -198,38 +192,38 @@ pub enum ListEntrySize { } #[derive(Component)] -pub enum ListItem { - Entry(ListEntry), +pub enum ListItem { + Entry(ListEntry), Details(ListDetailsEntry), - Separator(ListSeparator), - Header(ListSubHeader), + Separator(ListSeparator), + Header(ListSubHeader), } -impl From> for ListItem { - fn from(entry: ListEntry) -> Self { +impl From for ListItem { + fn from(entry: ListEntry) -> Self { Self::Entry(entry) } } -impl From> for ListItem { +impl From> for ListItem { fn from(entry: ListDetailsEntry) -> Self { Self::Details(entry) } } -impl From> for ListItem { - fn from(entry: ListSeparator) -> Self { +impl From for ListItem { + fn from(entry: ListSeparator) -> Self { Self::Separator(entry) } } -impl From> for ListItem { - fn from(entry: ListSubHeader) -> Self { +impl From for ListItem { + fn from(entry: ListSubHeader) -> Self { Self::Header(entry) } } -impl ListItem { +impl ListItem { fn render(self, view: &mut S, cx: &mut ViewContext) -> impl Component { match self { ListItem::Entry(entry) => div().child(entry.render(view, cx)), @@ -239,11 +233,11 @@ impl ListItem { } } - pub fn new(label: Label) -> Self { + pub fn new(label: Label) -> Self { Self::Entry(ListEntry::new(label)) } - pub fn as_entry(&mut self) -> Option<&mut ListEntry> { + pub fn as_entry(&mut self) -> Option<&mut ListEntry> { if let Self::Entry(entry) = self { Some(entry) } else { @@ -253,10 +247,10 @@ impl ListItem { } #[derive(Component)] -pub struct ListEntry { +pub struct ListEntry { disclosure_control_style: DisclosureControlVisibility, indent_level: u32, - label: Option>, + label: Option