Merge branch 'main' into clippy-fixes-for-zed2

Piotr Osiewicz created

Change summary

crates/collab2/src/tests/test_server.rs                       |   2 
crates/collab_ui2/src/face_pile.rs                            |   4 
crates/copilot2/src/copilot2.rs                               |   2 
crates/editor2/src/element.rs                                 |   2 
crates/gpui2/src/element.rs                                   | 128 ++--
crates/gpui2/src/elements/canvas.rs                           |   2 
crates/gpui2/src/elements/div.rs                              |  10 
crates/gpui2/src/elements/img.rs                              |   2 
crates/gpui2/src/elements/list.rs                             |   2 
crates/gpui2/src/elements/overlay.rs                          |   2 
crates/gpui2/src/elements/svg.rs                              |   2 
crates/gpui2/src/elements/text.rs                             |  12 
crates/gpui2/src/elements/uniform_list.rs                     |   2 
crates/gpui2/src/platform/mac.rs                              |  32 -
crates/gpui2/src/platform/mac/events.rs                       |   2 
crates/gpui2/src/platform/mac/window.rs                       |   1 
crates/gpui2/src/scene.rs                                     |   1 
crates/gpui2/src/view.rs                                      |  10 
crates/quick_action_bar2/src/quick_action_bar.rs              |   4 
crates/recent_projects2/src/highlighted_workspace_location.rs |   4 
crates/search2/src/buffer_search.rs                           |  10 
crates/search2/src/project_search.rs                          |  84 ++
crates/story/src/story.rs                                     |  12 
crates/storybook2/src/stories/z_index.rs                      |   4 
crates/terminal_view2/src/terminal_element.rs                 |   2 
crates/text2/src/text2.rs                                     |   3 
crates/ui2/src/components/avatar.rs                           |   4 
crates/ui2/src/components/button/button.rs                    |   4 
crates/ui2/src/components/button/button_icon.rs               |   4 
crates/ui2/src/components/button/button_like.rs               |   4 
crates/ui2/src/components/button/icon_button.rs               |   4 
crates/ui2/src/components/button/toggle_button.rs             |   4 
crates/ui2/src/components/checkbox.rs                         |   4 
crates/ui2/src/components/disclosure.rs                       |   4 
crates/ui2/src/components/divider.rs                          |   4 
crates/ui2/src/components/icon.rs                             |   4 
crates/ui2/src/components/indicator.rs                        |   4 
crates/ui2/src/components/keybinding.rs                       |  12 
crates/ui2/src/components/label/highlighted_label.rs          |   4 
crates/ui2/src/components/label/label.rs                      |   4 
crates/ui2/src/components/label/label_like.rs                 |   4 
crates/ui2/src/components/list/list.rs                        |   4 
crates/ui2/src/components/list/list_header.rs                 |   4 
crates/ui2/src/components/list/list_item.rs                   |   4 
crates/ui2/src/components/list/list_separator.rs              |   4 
crates/ui2/src/components/list/list_sub_header.rs             |   4 
crates/ui2/src/components/popover.rs                          |   4 
crates/ui2/src/components/popover_menu.rs                     |   2 
crates/ui2/src/components/right_click_menu.rs                 |   2 
crates/ui2/src/components/tab.rs                              |   4 
crates/ui2/src/components/tab_bar.rs                          |   4 
crates/workspace2/src/pane_group.rs                           |   2 
crates/workspace2/src/workspace2.rs                           |   2 
53 files changed, 238 insertions(+), 211 deletions(-)

Detailed changes

crates/collab2/src/tests/test_server.rs 🔗

@@ -260,8 +260,6 @@ impl TestServer {
             .store(true, SeqCst);
     }
 
-    //todo!(workspace)
-    #[allow(dead_code)]
     pub fn simulate_long_connection_interruption(
         &self,
         peer_id: PeerId,

crates/collab_ui2/src/face_pile.rs 🔗

@@ -9,9 +9,9 @@ pub struct FacePile {
 }
 
 impl RenderOnce for FacePile {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, _: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _: &mut WindowContext) -> Self::Output {
         let player_count = self.faces.len();
         let player_list = self.faces.into_iter().enumerate().map(|(ix, player)| {
             let isnt_last = ix < player_count - 1;

crates/copilot2/src/copilot2.rs 🔗

@@ -563,7 +563,6 @@ impl Copilot {
         }
     }
 
-    #[allow(dead_code)] // todo!()
     fn sign_out(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
         self.update_sign_in_status(request::SignInStatus::NotSignedIn, cx);
         if let CopilotServer::Running(RunningCopilotServer { lsp: server, .. }) = &self.server {
@@ -1126,7 +1125,6 @@ mod tests {
             .update(cx, |copilot, cx| copilot.sign_out(cx))
             .await
             .unwrap();
-        // todo!() po: these notifications now happen in reverse order?
         assert_eq!(
             lsp.receive_notification::<lsp::notification::DidCloseTextDocument>()
                 .await,

crates/editor2/src/element.rs 🔗

@@ -2757,7 +2757,7 @@ enum Invisible {
 impl Element for EditorElement {
     type State = ();
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _element_state: Option<Self::State>,
         cx: &mut gpui::WindowContext,

crates/gpui2/src/element.rs 🔗

@@ -6,21 +6,42 @@ use derive_more::{Deref, DerefMut};
 pub(crate) use smallvec::SmallVec;
 use std::{any::Any, fmt::Debug};
 
-pub trait Render: 'static + Sized {
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element;
+pub trait Element: 'static + IntoElement {
+    type State: 'static;
+
+    fn request_layout(
+        &mut self,
+        state: Option<Self::State>,
+        cx: &mut WindowContext,
+    ) -> (LayoutId, Self::State);
+
+    fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext);
+
+    fn into_any(self) -> AnyElement {
+        AnyElement::new(self)
+    }
 }
 
+/// Implemented by any type that can be converted into an element.
 pub trait IntoElement: Sized {
-    type Element: Element + 'static;
+    /// The specific type of element into which the implementing type is converted.
+    type Element: Element;
 
+    /// The [ElementId] of self once converted into an [Element].
+    /// If present, the resulting element's state will be carried across frames.
     fn element_id(&self) -> Option<ElementId>;
 
+    /// Convert self into a type that implements [Element].
     fn into_element(self) -> Self::Element;
 
+    /// Convert self into a dynamically-typed [AnyElement].
     fn into_any_element(self) -> AnyElement {
         self.into_element().into_any()
     }
 
+    /// Convert into an element, then draw in the current window at the given origin.
+    /// The provided available space is provided to the layout engine to determine the size of the root element.
+    /// Once the element is drawn, its associated element staet is yielded to the given callback.
     fn draw_and_update_state<T, R>(
         self,
         origin: Point<Pixels>,
@@ -52,6 +73,7 @@ pub trait IntoElement: Sized {
         }
     }
 
+    /// Convert self to another type by calling the given closure. Useful in rendering code.
     fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
     where
         Self: Sized,
@@ -60,6 +82,7 @@ pub trait IntoElement: Sized {
         f(self)
     }
 
+    /// Conditionally chain onto self with the given closure. Useful in rendering code.
     fn when(self, condition: bool, then: impl FnOnce(Self) -> Self) -> Self
     where
         Self: Sized,
@@ -67,6 +90,8 @@ pub trait IntoElement: Sized {
         self.map(|this| if condition { then(this) } else { this })
     }
 
+    /// Conditionally chain onto self with the given closure if the given option is Some.
+    /// The contents of the option are provided to the closure.
     fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
     where
         Self: Sized,
@@ -81,35 +106,46 @@ pub trait IntoElement: Sized {
     }
 }
 
-pub trait Element: 'static + IntoElement {
-    type State: 'static;
-
-    fn layout(
-        &mut self,
-        state: Option<Self::State>,
-        cx: &mut WindowContext,
-    ) -> (LayoutId, Self::State);
+pub trait Render: 'static + Sized {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element;
+}
 
-    fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext);
+/// You can derive [IntoElement] on any type that implements this trait.
+/// It is used to allow views to be expressed in terms of abstract data.
+pub trait RenderOnce: 'static {
+    type Output: IntoElement;
 
-    fn into_any(self) -> AnyElement {
-        AnyElement::new(self)
-    }
+    fn render(self, cx: &mut WindowContext) -> Self::Output;
 }
 
-pub trait RenderOnce: 'static {
-    type Rendered: IntoElement;
+pub trait ParentElement {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered;
+    fn child(mut self, child: impl IntoElement) -> Self
+    where
+        Self: Sized,
+    {
+        self.children_mut().push(child.into_element().into_any());
+        self
+    }
+
+    fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self
+    where
+        Self: Sized,
+    {
+        self.children_mut()
+            .extend(children.into_iter().map(|child| child.into_any_element()));
+        self
+    }
 }
 
 pub struct Component<C> {
     component: Option<C>,
 }
 
-pub struct CompositeElementState<C: RenderOnce> {
-    rendered_element: Option<<C::Rendered as IntoElement>::Element>,
-    rendered_element_state: Option<<<C::Rendered as IntoElement>::Element as Element>::State>,
+pub struct ComponentState<C: RenderOnce> {
+    rendered_element: Option<<C::Output as IntoElement>::Element>,
+    rendered_element_state: Option<<<C::Output as IntoElement>::Element as Element>::State>,
 }
 
 impl<C> Component<C> {
@@ -121,9 +157,9 @@ impl<C> Component<C> {
 }
 
 impl<C: RenderOnce> Element for Component<C> {
-    type State = CompositeElementState<C>;
+    type State = ComponentState<C>;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         state: Option<Self::State>,
         cx: &mut WindowContext,
@@ -131,16 +167,16 @@ impl<C: RenderOnce> Element for Component<C> {
         let mut element = self.component.take().unwrap().render(cx).into_element();
         if let Some(element_id) = element.element_id() {
             let layout_id =
-                cx.with_element_state(element_id, |state, cx| element.layout(state, cx));
-            let state = CompositeElementState {
+                cx.with_element_state(element_id, |state, cx| element.request_layout(state, cx));
+            let state = ComponentState {
                 rendered_element: Some(element),
                 rendered_element_state: None,
             };
             (layout_id, state)
         } else {
             let (layout_id, state) =
-                element.layout(state.and_then(|s| s.rendered_element_state), cx);
-            let state = CompositeElementState {
+                element.request_layout(state.and_then(|s| s.rendered_element_state), cx);
+            let state = ComponentState {
                 rendered_element: Some(element),
                 rendered_element_state: Some(state),
             };
@@ -181,27 +217,6 @@ impl<C: RenderOnce> IntoElement for Component<C> {
 #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
 
-pub trait ParentElement {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>;
-
-    fn child(mut self, child: impl IntoElement) -> Self
-    where
-        Self: Sized,
-    {
-        self.children_mut().push(child.into_element().into_any());
-        self
-    }
-
-    fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self
-    where
-        Self: Sized,
-    {
-        self.children_mut()
-            .extend(children.into_iter().map(|child| child.into_any_element()));
-        self
-    }
-}
-
 trait ElementObject {
     fn element_id(&self) -> Option<ElementId>;
 
@@ -256,15 +271,18 @@ impl<E: Element> DrawableElement<E> {
         self.element.as_ref()?.element_id()
     }
 
-    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
+    fn request_layout(&mut self, cx: &mut WindowContext) -> LayoutId {
         let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
         {
             let layout_id = cx.with_element_state(id, |element_state, cx| {
-                self.element.as_mut().unwrap().layout(element_state, cx)
+                self.element
+                    .as_mut()
+                    .unwrap()
+                    .request_layout(element_state, cx)
             });
             (layout_id, None)
         } else {
-            let (layout_id, frame_state) = self.element.as_mut().unwrap().layout(None, cx);
+            let (layout_id, frame_state) = self.element.as_mut().unwrap().request_layout(None, cx);
             (layout_id, Some(frame_state))
         };
 
@@ -323,7 +341,7 @@ impl<E: Element> DrawableElement<E> {
         cx: &mut WindowContext,
     ) -> Size<Pixels> {
         if matches!(&self.phase, ElementDrawPhase::Start) {
-            self.layout(cx);
+            self.request_layout(cx);
         }
 
         let layout_id = match &mut self.phase {
@@ -378,7 +396,7 @@ where
     }
 
     fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
-        DrawableElement::layout(self.as_mut().unwrap(), cx)
+        DrawableElement::request_layout(self.as_mut().unwrap(), cx)
     }
 
     fn paint(&mut self, cx: &mut WindowContext) {
@@ -452,7 +470,7 @@ impl AnyElement {
 impl Element for AnyElement {
     type State = ();
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _: Option<Self::State>,
         cx: &mut WindowContext,
@@ -500,7 +518,7 @@ impl IntoElement for () {
 impl Element for () {
     type State = ();
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _state: Option<Self::State>,
         cx: &mut WindowContext,

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

@@ -29,7 +29,7 @@ impl IntoElement for Canvas {
 impl Element for Canvas {
     type State = Style;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _: Option<Self::State>,
         cx: &mut WindowContext,

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

@@ -765,7 +765,7 @@ impl ParentElement for Div {
 impl Element for Div {
     type State = DivState;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         element_state: Option<Self::State>,
         cx: &mut WindowContext,
@@ -1808,12 +1808,12 @@ where
 {
     type State = E::State;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         state: Option<Self::State>,
         cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
-        self.element.layout(state, cx)
+        self.element.request_layout(state, cx)
     }
 
     fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
@@ -1882,12 +1882,12 @@ where
 {
     type State = E::State;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         state: Option<Self::State>,
         cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
-        self.element.layout(state, cx)
+        self.element.request_layout(state, cx)
     }
 
     fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {

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

@@ -71,7 +71,7 @@ impl Img {
 impl Element for Img {
     type State = InteractiveElementState;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         element_state: Option<Self::State>,
         cx: &mut WindowContext,

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

@@ -302,7 +302,7 @@ pub struct ListOffset {
 impl Element for List {
     type State = ();
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _state: Option<Self::State>,
         cx: &mut crate::WindowContext,

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

@@ -60,7 +60,7 @@ impl ParentElement for Overlay {
 impl Element for Overlay {
     type State = OverlayState;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _: Option<Self::State>,
         cx: &mut WindowContext,

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

@@ -26,7 +26,7 @@ impl Svg {
 impl Element for Svg {
     type State = InteractiveElementState;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         element_state: Option<Self::State>,
         cx: &mut WindowContext,

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

@@ -12,7 +12,7 @@ use util::ResultExt;
 impl Element for &'static str {
     type State = TextState;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _: Option<Self::State>,
         cx: &mut WindowContext,
@@ -42,7 +42,7 @@ impl IntoElement for &'static str {
 impl Element for SharedString {
     type State = TextState;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _: Option<Self::State>,
         cx: &mut WindowContext,
@@ -118,7 +118,7 @@ impl StyledText {
 impl Element for StyledText {
     type State = TextState;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _: Option<Self::State>,
         cx: &mut WindowContext,
@@ -331,7 +331,7 @@ impl InteractiveText {
 impl Element for InteractiveText {
     type State = InteractiveTextState;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         state: Option<Self::State>,
         cx: &mut WindowContext,
@@ -340,14 +340,14 @@ impl Element for InteractiveText {
             mouse_down_index, ..
         }) = state
         {
-            let (layout_id, text_state) = self.text.layout(None, cx);
+            let (layout_id, text_state) = self.text.request_layout(None, cx);
             let element_state = InteractiveTextState {
                 text_state,
                 mouse_down_index,
             };
             (layout_id, element_state)
         } else {
-            let (layout_id, text_state) = self.text.layout(None, cx);
+            let (layout_id, text_state) = self.text.request_layout(None, cx);
             let element_state = InteractiveTextState {
                 text_state,
                 mouse_down_index: Rc::default(),

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

@@ -116,7 +116,7 @@ pub struct UniformListState {
 impl Element for UniformList {
     type State = UniformListState;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         state: Option<Self::State>,
         cx: &mut WindowContext,

crates/gpui2/src/platform/mac.rs 🔗

@@ -13,23 +13,13 @@ mod window;
 mod window_appearence;
 
 use crate::{px, size, GlobalPixels, Pixels, Size};
-use anyhow::anyhow;
 use cocoa::{
     base::{id, nil},
-    foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger, NSURL},
+    foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger},
 };
 use metal_renderer::*;
-use objc::{
-    msg_send,
-    runtime::{BOOL, NO, YES},
-    sel, sel_impl,
-};
-use std::{
-    ffi::{c_char, CStr, OsStr},
-    ops::Range,
-    os::unix::prelude::OsStrExt,
-    path::PathBuf,
-};
+use objc::runtime::{BOOL, NO, YES};
+use std::ops::Range;
 
 pub use dispatcher::*;
 pub use display::*;
@@ -147,19 +137,3 @@ impl From<NSRect> for Size<GlobalPixels> {
 //             && self.origin.y + self.size.height >= other.origin.y
 //     }
 // }
-
-// todo!
-#[allow(unused)]
-unsafe fn ns_url_to_path(url: id) -> crate::Result<PathBuf> {
-    let path: *mut c_char = msg_send![url, fileSystemRepresentation];
-    if path.is_null() {
-        Err(anyhow!(
-            "url is not a file path: {}",
-            CStr::from_ptr(url.absoluteString().UTF8String()).to_string_lossy()
-        ))
-    } else {
-        Ok(PathBuf::from(OsStr::from_bytes(
-            CStr::from_ptr(path).to_bytes(),
-        )))
-    }
-}

crates/gpui2/src/platform/mac/events.rs 🔗

@@ -34,8 +34,6 @@ unsafe fn build_event_source() {
     mem::forget(source);
 }
 
-// todo!
-#[allow(unused)]
 pub fn key_to_native(key: &str) -> Cow<str> {
     use cocoa::appkit::*;
     let code = match key {

crates/gpui2/src/platform/mac/window.rs 🔗

@@ -74,7 +74,6 @@ const NSWindowAnimationBehaviorUtilityWindow: NSInteger = 4;
 #[allow(non_upper_case_globals)]
 const NSViewLayerContentsRedrawDuringViewResize: NSInteger = 2;
 // https://developer.apple.com/documentation/appkit/nsdragoperation
-#[allow(non_upper_case_globals)]
 type NSDragOperation = NSUInteger;
 #[allow(non_upper_case_globals)]
 const NSDragOperationNone: NSDragOperation = 0;

crates/gpui2/src/scene.rs 🔗

@@ -159,7 +159,6 @@ pub struct Scene {
 }
 
 impl Scene {
-    #[allow(dead_code)]
     pub fn paths(&self) -> &[Path<ScaledPixels>] {
         &self.paths
     }

crates/gpui2/src/view.rs 🔗

@@ -81,12 +81,12 @@ impl<V: 'static> View<V> {
 impl<V: Render> Element for View<V> {
     type State = Option<AnyElement>;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _state: Option<Self::State>,
         cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
-        let mut element = self.update(cx, |view, cx| view.render(cx).into_any());
+        let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element());
         let layout_id = element.layout(cx);
         (layout_id, Some(element))
     }
@@ -229,7 +229,7 @@ impl<V: Render> From<View<V>> for AnyView {
 impl Element for AnyView {
     type State = Option<AnyElement>;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _state: Option<Self::State>,
         cx: &mut WindowContext,
@@ -313,14 +313,14 @@ impl std::fmt::Debug for AnyWeakView {
 }
 
 mod any_view {
-    use crate::{AnyElement, AnyView, Element, LayoutId, Render, WindowContext};
+    use crate::{AnyElement, AnyView, IntoElement, LayoutId, Render, WindowContext};
 
     pub(crate) fn layout<V: 'static + Render>(
         view: &AnyView,
         cx: &mut WindowContext,
     ) -> (LayoutId, AnyElement) {
         let view = view.clone().downcast::<V>().unwrap();
-        let mut element = view.update(cx, |view, cx| view.render(cx).into_any());
+        let mut element = view.update(cx, |view, cx| view.render(cx).into_any_element());
         let layout_id = element.layout(cx);
         (layout_id, element)
     }

crates/quick_action_bar2/src/quick_action_bar.rs 🔗

@@ -136,9 +136,9 @@ impl QuickActionBarButton {
 }
 
 impl RenderOnce for QuickActionBarButton {
-    type Rendered = IconButton;
+    type Output = IconButton;
 
-    fn render(self, _: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _: &mut WindowContext) -> Self::Output {
         let tooltip = self.tooltip.clone();
         let action = self.action.boxed_clone();
 

crates/recent_projects2/src/highlighted_workspace_location.rs 🔗

@@ -43,9 +43,9 @@ impl HighlightedText {
 }
 
 impl RenderOnce for HighlightedText {
-    type Rendered = HighlightedLabel;
+    type Output = HighlightedLabel;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         HighlightedLabel::new(self.text, self.highlight_positions)
     }
 }

crates/search2/src/buffer_search.rs 🔗

@@ -181,7 +181,11 @@ impl Render for BufferSearchBar {
         if in_replace {
             key_context.add("in_replace");
         }
-
+        let editor_border = if self.query_contains_error {
+            Color::Error.color(cx)
+        } else {
+            cx.theme().colors().border
+        };
         h_stack()
             .w_full()
             .gap_2()
@@ -217,7 +221,7 @@ impl Render for BufferSearchBar {
                     .py_1()
                     .gap_2()
                     .border_1()
-                    .border_color(cx.theme().colors().border)
+                    .border_color(editor_border)
                     .rounded_lg()
                     .child(IconElement::new(Icon::MagnifyingGlass))
                     .child(self.render_text_input(&self.query_editor, cx))
@@ -852,6 +856,7 @@ impl BufferSearchBar {
                         Ok(query) => query.with_replacement(self.replacement(cx)),
                         Err(_) => {
                             self.query_contains_error = true;
+                            self.active_match_index = None;
                             cx.notify();
                             return done_rx;
                         }
@@ -868,6 +873,7 @@ impl BufferSearchBar {
                         Ok(query) => query.with_replacement(self.replacement(cx)),
                         Err(_) => {
                             self.query_contains_error = true;
+                            self.active_match_index = None;
                             cx.notify();
                             return done_rx;
                         }

crates/search2/src/project_search.rs 🔗

@@ -13,10 +13,10 @@ use editor::{
 use editor::{EditorElement, EditorStyle};
 use gpui::{
     actions, div, AnyElement, AnyView, AppContext, Context as _, Element, EntityId, EventEmitter,
-    FocusHandle, FocusableView, FontStyle, FontWeight, InteractiveElement, IntoElement, KeyContext,
-    Model, ModelContext, ParentElement, PromptLevel, Render, SharedString, Styled, Subscription,
-    Task, TextStyle, View, ViewContext, VisualContext, WeakModel, WeakView, WhiteSpace,
-    WindowContext,
+    FocusHandle, FocusableView, FontStyle, FontWeight, Hsla, InteractiveElement, IntoElement,
+    KeyContext, Model, ModelContext, ParentElement, PromptLevel, Render, SharedString, Styled,
+    Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakModel, WeakView,
+    WhiteSpace, WindowContext,
 };
 use menu::Confirm;
 use project::{
@@ -1007,33 +1007,46 @@ impl ProjectSearchView {
     }
 
     fn build_search_query(&mut self, cx: &mut ViewContext<Self>) -> Option<SearchQuery> {
+        // Do not bail early in this function, as we want to fill out `self.panels_with_errors`.
         let text = self.query_editor.read(cx).text(cx);
         let included_files =
             match Self::parse_path_matches(&self.included_files_editor.read(cx).text(cx)) {
                 Ok(included_files) => {
-                    self.panels_with_errors.remove(&InputPanel::Include);
+                    let should_unmark_error = self.panels_with_errors.remove(&InputPanel::Include);
+                    if should_unmark_error {
+                        cx.notify();
+                    }
                     included_files
                 }
                 Err(_e) => {
-                    self.panels_with_errors.insert(InputPanel::Include);
-                    cx.notify();
-                    return None;
+                    let should_mark_error = self.panels_with_errors.insert(InputPanel::Include);
+                    if should_mark_error {
+                        cx.notify();
+                    }
+                    vec![]
                 }
             };
         let excluded_files =
             match Self::parse_path_matches(&self.excluded_files_editor.read(cx).text(cx)) {
                 Ok(excluded_files) => {
-                    self.panels_with_errors.remove(&InputPanel::Exclude);
+                    let should_unmark_error = self.panels_with_errors.remove(&InputPanel::Exclude);
+                    if should_unmark_error {
+                        cx.notify();
+                    }
+
                     excluded_files
                 }
                 Err(_e) => {
-                    self.panels_with_errors.insert(InputPanel::Exclude);
-                    cx.notify();
-                    return None;
+                    let should_mark_error = self.panels_with_errors.insert(InputPanel::Exclude);
+                    if should_mark_error {
+                        cx.notify();
+                    }
+                    vec![]
                 }
             };
+
         let current_mode = self.current_mode;
-        match current_mode {
+        let query = match current_mode {
             SearchMode::Regex => {
                 match SearchQuery::regex(
                     text,
@@ -1044,12 +1057,20 @@ impl ProjectSearchView {
                     excluded_files,
                 ) {
                     Ok(query) => {
-                        self.panels_with_errors.remove(&InputPanel::Query);
+                        let should_unmark_error =
+                            self.panels_with_errors.remove(&InputPanel::Query);
+                        if should_unmark_error {
+                            cx.notify();
+                        }
+
                         Some(query)
                     }
                     Err(_e) => {
-                        self.panels_with_errors.insert(InputPanel::Query);
-                        cx.notify();
+                        let should_mark_error = self.panels_with_errors.insert(InputPanel::Query);
+                        if should_mark_error {
+                            cx.notify();
+                        }
+
                         None
                     }
                 }
@@ -1063,16 +1084,27 @@ impl ProjectSearchView {
                 excluded_files,
             ) {
                 Ok(query) => {
-                    self.panels_with_errors.remove(&InputPanel::Query);
+                    let should_unmark_error = self.panels_with_errors.remove(&InputPanel::Query);
+                    if should_unmark_error {
+                        cx.notify();
+                    }
+
                     Some(query)
                 }
                 Err(_e) => {
-                    self.panels_with_errors.insert(InputPanel::Query);
-                    cx.notify();
+                    let should_mark_error = self.panels_with_errors.insert(InputPanel::Query);
+                    if should_mark_error {
+                        cx.notify();
+                    }
+
                     None
                 }
             },
+        };
+        if !self.panels_with_errors.is_empty() {
+            return None;
         }
+        query
     }
 
     fn parse_path_matches(text: &str) -> anyhow::Result<Vec<PathMatcher>> {
@@ -1185,6 +1217,13 @@ impl ProjectSearchView {
             SearchMode::Semantic => "\nSimply explain the code you are looking to find. ex. 'prompt user for permissions to index their project'".into()
         }
     }
+    fn border_color_for(&self, panel: InputPanel, cx: &WindowContext) -> Hsla {
+        if self.panels_with_errors.contains(&panel) {
+            Color::Error.color(cx)
+        } else {
+            cx.theme().colors().border
+        }
+    }
 }
 
 impl Default for ProjectSearchBar {
@@ -1507,6 +1546,7 @@ impl Render for ProjectSearchBar {
         }
         let search = search.read(cx);
         let semantic_is_available = SemanticIndex::enabled(cx);
+
         let query_column = v_stack().child(
             h_stack()
                 .min_w(rems(512. / 16.))
@@ -1515,7 +1555,7 @@ impl Render for ProjectSearchBar {
                 .gap_2()
                 .bg(cx.theme().colors().editor_background)
                 .border_1()
-                .border_color(cx.theme().colors().border)
+                .border_color(search.border_color_for(InputPanel::Query, cx))
                 .rounded_lg()
                 .on_action(cx.listener(|this, action, cx| this.confirm(action, cx)))
                 .on_action(cx.listener(|this, action, cx| this.previous_history_query(action, cx)))
@@ -1789,7 +1829,7 @@ impl Render for ProjectSearchBar {
                                 .px_2()
                                 .py_1()
                                 .border_1()
-                                .border_color(cx.theme().colors().border)
+                                .border_color(search.border_color_for(InputPanel::Include, cx))
                                 .rounded_lg()
                                 .child(self.render_text_input(&search.included_files_editor, cx))
                                 .when(search.current_mode != SearchMode::Semantic, |this| {
@@ -1815,7 +1855,7 @@ impl Render for ProjectSearchBar {
                                 .px_2()
                                 .py_1()
                                 .border_1()
-                                .border_color(cx.theme().colors().border)
+                                .border_color(search.border_color_for(InputPanel::Exclude, cx))
                                 .rounded_lg()
                                 .child(self.render_text_input(&search.excluded_files_editor, cx)),
                         ),

crates/story/src/story.rs 🔗

@@ -74,9 +74,9 @@ impl ParentElement for StoryContainer {
 }
 
 impl RenderOnce for StoryContainer {
-    type Rendered = Stateful<Div>;
+    type Output = Stateful<Div>;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         div()
             .size_full()
             .flex()
@@ -294,9 +294,9 @@ impl StoryItem {
 }
 
 impl RenderOnce for StoryItem {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         div()
             .my_2()
             .flex()
@@ -358,9 +358,9 @@ impl StorySection {
 }
 
 impl RenderOnce for StorySection {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         let children: SmallVec<[AnyElement; 2]> = SmallVec::from_iter(Itertools::intersperse_with(
             self.children.into_iter(),
             || Story::divider().into_any_element(),

crates/storybook2/src/stories/z_index.rs 🔗

@@ -80,9 +80,9 @@ struct ZIndexExample {
 }
 
 impl RenderOnce for ZIndexExample {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         div()
             .relative()
             .size_full()

crates/terminal_view2/src/terminal_element.rs 🔗

@@ -750,7 +750,7 @@ impl TerminalElement {
 impl Element for TerminalElement {
     type State = InteractiveElementState;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         element_state: Option<Self::State>,
         cx: &mut WindowContext<'_>,

crates/text2/src/text2.rs 🔗

@@ -1189,7 +1189,6 @@ impl Buffer {
         self.undo_or_redo(transaction).log_err()
     }
 
-    #[allow(clippy::needless_collect)]
     pub fn undo_to_transaction(&mut self, transaction_id: TransactionId) -> Vec<Operation> {
         let transactions = self
             .history
@@ -1223,7 +1222,6 @@ impl Buffer {
         }
     }
 
-    #[allow(clippy::needless_collect)]
     pub fn redo_to_transaction(&mut self, transaction_id: TransactionId) -> Vec<Operation> {
         let transactions = self
             .history
@@ -1536,7 +1534,6 @@ impl Buffer {
         edits
     }
 
-    #[allow(clippy::type_complexity)]
     pub fn randomly_edit<T>(
         &mut self,
         rng: &mut T,

crates/ui2/src/components/avatar.rs 🔗

@@ -16,9 +16,9 @@ pub struct Avatar {
 }
 
 impl RenderOnce for Avatar {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(mut self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(mut self, cx: &mut WindowContext) -> Self::Output {
         if self.image.style().corner_radii.top_left.is_none() {
             self = self.shape(Shape::Circle);
         }

crates/ui2/src/components/button/button.rs 🔗

@@ -136,9 +136,9 @@ impl ButtonCommon for Button {
 }
 
 impl RenderOnce for Button {
-    type Rendered = ButtonLike;
+    type Output = ButtonLike;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         let is_disabled = self.base.disabled;
         let is_selected = self.base.selected;
 

crates/ui2/src/components/button/button_icon.rs 🔗

@@ -63,9 +63,9 @@ impl Selectable for ButtonIcon {
 }
 
 impl RenderOnce for ButtonIcon {
-    type Rendered = IconElement;
+    type Output = IconElement;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         let icon = self
             .selected_icon
             .filter(|_| self.selected)

crates/ui2/src/components/button/button_like.rs 🔗

@@ -363,9 +363,9 @@ impl ParentElement for ButtonLike {
 }
 
 impl RenderOnce for ButtonLike {
-    type Rendered = Stateful<Div>;
+    type Output = Stateful<Div>;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         self.base
             .h_flex()
             .id(self.id.clone())

crates/ui2/src/components/button/icon_button.rs 🔗

@@ -106,9 +106,9 @@ impl VisibleOnHover for IconButton {
 }
 
 impl RenderOnce for IconButton {
-    type Rendered = ButtonLike;
+    type Output = ButtonLike;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         let is_disabled = self.base.disabled;
         let is_selected = self.base.selected;
 

crates/ui2/src/components/button/toggle_button.rs 🔗

@@ -99,9 +99,9 @@ impl ButtonCommon for ToggleButton {
 }
 
 impl RenderOnce for ToggleButton {
-    type Rendered = ButtonLike;
+    type Output = ButtonLike;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         let is_disabled = self.base.disabled;
         let is_selected = self.base.selected;
 

crates/ui2/src/components/checkbox.rs 🔗

@@ -19,9 +19,9 @@ pub struct Checkbox {
 }
 
 impl RenderOnce for Checkbox {
-    type Rendered = gpui::Stateful<Div>;
+    type Output = gpui::Stateful<Div>;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         let group_id = format!("checkbox_group_{:?}", self.id);
 
         let icon = match self.checked {

crates/ui2/src/components/disclosure.rs 🔗

@@ -28,9 +28,9 @@ impl Disclosure {
 }
 
 impl RenderOnce for Disclosure {
-    type Rendered = IconButton;
+    type Output = IconButton;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         IconButton::new(
             self.id,
             match self.is_open {

crates/ui2/src/components/divider.rs 🔗

@@ -31,9 +31,9 @@ pub struct Divider {
 }
 
 impl RenderOnce for Divider {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         div()
             .map(|this| match self.direction {
                 DividerDirection::Horizontal => {

crates/ui2/src/components/icon.rs 🔗

@@ -196,9 +196,9 @@ pub struct IconElement {
 }
 
 impl RenderOnce for IconElement {
-    type Rendered = Svg;
+    type Output = Svg;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         svg()
             .size(self.size.rems())
             .flex_none()

crates/ui2/src/components/indicator.rs 🔗

@@ -45,9 +45,9 @@ impl Indicator {
 }
 
 impl RenderOnce for Indicator {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         div()
             .flex_none()
             .map(|this| match self.style {

crates/ui2/src/components/keybinding.rs 🔗

@@ -11,9 +11,9 @@ pub struct KeyBinding {
 }
 
 impl RenderOnce for KeyBinding {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         h_stack()
             .flex_none()
             .gap_2()
@@ -91,9 +91,9 @@ pub struct Key {
 }
 
 impl RenderOnce for Key {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         let single_char = self.key.len() == 1;
 
         div()
@@ -125,9 +125,9 @@ pub struct KeyIcon {
 }
 
 impl RenderOnce for KeyIcon {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         div()
             .w(rems(14. / 16.))
             .child(IconElement::new(self.icon).size(IconSize::Small))

crates/ui2/src/components/label/highlighted_label.rs 🔗

@@ -46,9 +46,9 @@ impl LabelCommon for HighlightedLabel {
 }
 
 impl RenderOnce for HighlightedLabel {
-    type Rendered = LabelLike;
+    type Output = LabelLike;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         let highlight_color = cx.theme().colors().text_accent;
 
         let mut highlight_indices = self.highlight_indices.iter().copied().peekable();

crates/ui2/src/components/label/label.rs 🔗

@@ -40,9 +40,9 @@ impl LabelCommon for Label {
 }
 
 impl RenderOnce for Label {
-    type Rendered = LabelLike;
+    type Output = LabelLike;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         self.base.child(self.label)
     }
 }

crates/ui2/src/components/label/label_like.rs 🔗

@@ -76,9 +76,9 @@ impl ParentElement for LabelLike {
 }
 
 impl RenderOnce for LabelLike {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         div()
             .when(self.strikethrough, |this| {
                 this.relative().child(

crates/ui2/src/components/list/list.rs 🔗

@@ -46,9 +46,9 @@ impl ParentElement for List {
 }
 
 impl RenderOnce for List {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         v_stack().w_full().py_1().children(self.header).map(|this| {
             match (self.children.is_empty(), self.toggle) {
                 (false, _) => this.children(self.children),

crates/ui2/src/components/list/list_header.rs 🔗

@@ -76,9 +76,9 @@ impl Selectable for ListHeader {
 }
 
 impl RenderOnce for ListHeader {
-    type Rendered = Stateful<Div>;
+    type Output = Stateful<Div>;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         h_stack()
             .id(self.label.clone())
             .w_full()

crates/ui2/src/components/list/list_item.rs 🔗

@@ -147,9 +147,9 @@ impl ParentElement for ListItem {
 }
 
 impl RenderOnce for ListItem {
-    type Rendered = Stateful<Div>;
+    type Output = Stateful<Div>;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         h_stack()
             .id(self.id)
             .w_full()

crates/ui2/src/components/list/list_separator.rs 🔗

@@ -6,9 +6,9 @@ use crate::prelude::*;
 pub struct ListSeparator;
 
 impl RenderOnce for ListSeparator {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         div()
             .h_px()
             .w_full()

crates/ui2/src/components/list/list_sub_header.rs 🔗

@@ -26,9 +26,9 @@ impl ListSubHeader {
 }
 
 impl RenderOnce for ListSubHeader {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, _cx: &mut WindowContext) -> Self::Output {
         h_stack().flex_1().w_full().relative().py_1().child(
             div()
                 .h_6()

crates/ui2/src/components/popover.rs 🔗

@@ -41,9 +41,9 @@ pub struct Popover {
 }
 
 impl RenderOnce for Popover {
-    type Rendered = Div;
+    type Output = Div;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         div()
             .flex()
             .gap_1()

crates/ui2/src/components/popover_menu.rs 🔗

@@ -130,7 +130,7 @@ pub struct PopoverMenuState<M> {
 impl<M: ManagedView> Element for PopoverMenu<M> {
     type State = PopoverMenuState<M>;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         element_state: Option<Self::State>,
         cx: &mut WindowContext,

crates/ui2/src/components/right_click_menu.rs 🔗

@@ -60,7 +60,7 @@ pub struct MenuHandleState<M> {
 impl<M: ManagedView> Element for RightClickMenu<M> {
     type State = MenuHandleState<M>;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         element_state: Option<Self::State>,
         cx: &mut WindowContext,

crates/ui2/src/components/tab.rs 🔗

@@ -93,9 +93,9 @@ impl ParentElement for Tab {
 }
 
 impl RenderOnce for Tab {
-    type Rendered = Stateful<Div>;
+    type Output = Stateful<Div>;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         let (text_color, tab_bg, _tab_hover_bg, _tab_active_bg) = match self.selected {
             false => (
                 cx.theme().colors().text_muted,

crates/ui2/src/components/tab_bar.rs 🔗

@@ -89,9 +89,9 @@ impl ParentElement for TabBar {
 }
 
 impl RenderOnce for TabBar {
-    type Rendered = Stateful<Div>;
+    type Output = Stateful<Div>;
 
-    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Output {
         const HEIGHT_IN_REMS: f32 = 30. / 16.;
 
         div()

crates/workspace2/src/pane_group.rs 🔗

@@ -773,7 +773,7 @@ mod element {
     impl Element for PaneAxisElement {
         type State = Rc<RefCell<Option<usize>>>;
 
-        fn layout(
+        fn request_layout(
             &mut self,
             state: Option<Self::State>,
             cx: &mut ui::prelude::WindowContext,

crates/workspace2/src/workspace2.rs 🔗

@@ -4285,7 +4285,7 @@ struct DisconnectedOverlay;
 impl Element for DisconnectedOverlay {
     type State = AnyElement;
 
-    fn layout(
+    fn request_layout(
         &mut self,
         _: Option<Self::State>,
         cx: &mut WindowContext,