Clean compile with redesigned element traits

This commit is contained in:
Nathan Sobo 2023-11-18 21:51:47 -07:00
parent 0673606de8
commit 33cd6f520a
35 changed files with 278 additions and 216 deletions

View File

@ -3294,7 +3294,7 @@ impl CollabPanel {
// .with_width(size.x())
// }
impl Render for CollabPanel {
impl Render<Self> for CollabPanel {
type Element = Focusable<Self, Div<Self>>;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {

View File

@ -31,7 +31,7 @@ use std::sync::Arc;
use call::ActiveCall;
use client::{Client, UserStore};
use gpui::{
div, px, rems, AppContext, Component, Div, InteractiveElement, Model, ParentElement, Render,
div, px, rems, AppContext, Div, InteractiveElement, Model, ParentElement, Render, RenderOnce,
Stateful, StatefulInteractiveElement, Styled, Subscription, ViewContext, VisualContext,
WeakView, WindowBounds,
};
@ -81,7 +81,7 @@ pub struct CollabTitlebarItem {
_subscriptions: Vec<Subscription>,
}
impl Render for CollabTitlebarItem {
impl Render<Self> for CollabTitlebarItem {
type Element = Stateful<Self, Div<Self>>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {

View File

@ -1,7 +1,7 @@
use collections::{CommandPaletteFilter, HashMap};
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
actions, div, prelude::*, Action, AppContext, Component, Dismiss, Div, FocusHandle, Keystroke,
actions, div, prelude::*, Action, AppContext, Dismiss, Div, FocusHandle, Keystroke,
ManagedView, ParentElement, Render, Styled, View, ViewContext, VisualContext, WeakView,
};
use picker::{Picker, PickerDelegate};
@ -74,7 +74,7 @@ impl ManagedView for CommandPalette {
}
}
impl Render for CommandPalette {
impl Render<Self> for CommandPalette {
type Element = Div<Self>;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {

View File

@ -42,9 +42,9 @@ use gpui::{
actions, div, point, prelude::*, px, relative, rems, size, uniform_list, Action, AnyElement,
AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context,
EventEmitter, FocusHandle, FocusableView, FontFeatures, FontStyle, FontWeight, HighlightStyle,
Hsla, InputHandler, KeyContext, Model, MouseButton, ParentElement, Pixels, Render, Styled,
Subscription, Task, TextStyle, UniformListScrollHandle, View, ViewContext, VisualContext,
WeakView, WindowContext,
Hsla, InputHandler, KeyContext, Model, MouseButton, ParentElement, Pixels, Render,
SharedString, Styled, Subscription, Task, TextStyle, UniformListScrollHandle, View,
ViewContext, VisualContext, WeakView, WindowContext,
};
use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState};
@ -1580,7 +1580,8 @@ impl CodeActionsMenu {
)
.map(|task| task.detach_and_log_err(cx));
})
.child(action.lsp_action.title.clone())
// TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here.
.child(SharedString::from(action.lsp_action.title.clone()))
})
.collect()
},
@ -1595,7 +1596,7 @@ impl CodeActionsMenu {
.max_by_key(|(_, action)| action.lsp_action.title.chars().count())
.map(|(ix, _)| ix),
)
.render_once();
.render_into_any();
if self.deployed_from_indicator {
*cursor_position.column_mut() = 0;
@ -4353,19 +4354,19 @@ impl Editor {
style: &EditorStyle,
is_active: bool,
cx: &mut ViewContext<Self>,
) -> Option<AnyElement<Self>> {
) -> Option<IconButton<Self>> {
if self.available_code_actions.is_some() {
Some(
IconButton::new("code_actions_indicator", ui::Icon::Bolt)
.on_click(|editor: &mut Editor, cx| {
IconButton::new("code_actions_indicator", ui::Icon::Bolt).on_click(
|editor: &mut Editor, cx| {
editor.toggle_code_actions(
&ToggleCodeActions {
deployed_from_indicator: true,
},
cx,
);
})
.into_any(),
},
),
)
} else {
None
@ -4380,7 +4381,7 @@ impl Editor {
line_height: Pixels,
gutter_margin: Pixels,
cx: &mut ViewContext<Self>,
) -> Vec<Option<AnyElement<Self>>> {
) -> Vec<Option<IconButton<Self>>> {
fold_data
.iter()
.enumerate()
@ -4392,16 +4393,16 @@ impl Editor {
FoldStatus::Folded => ui::Icon::ChevronRight,
FoldStatus::Foldable => ui::Icon::ChevronDown,
};
IconButton::new(ix as usize, icon)
.on_click(move |editor: &mut Editor, cx| match fold_status {
IconButton::new(ix as usize, icon).on_click(
move |editor: &mut Editor, cx| match fold_status {
FoldStatus::Folded => {
editor.unfold_at(&UnfoldAt { buffer_row }, cx);
}
FoldStatus::Foldable => {
editor.fold_at(&FoldAt { buffer_row }, cx);
}
})
.into_any()
},
)
})
})
.flatten()
@ -7792,7 +7793,7 @@ impl Editor {
cx.editor_style.diagnostic_style.clone(),
},
)))
.render_once()
.render_into_any()
}
}),
disposition: BlockDisposition::Below,
@ -9994,7 +9995,7 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend
cx.write_to_clipboard(ClipboardItem::new(message.clone()));
})
.tooltip(|_, cx| Tooltip::text("Copy diagnostic message", cx))
.render_once()
.render_into_any()
})
}

View File

@ -3048,7 +3048,7 @@ fn test_move_line_up_down_with_blocks(cx: &mut TestAppContext) {
position: snapshot.anchor_after(Point::new(2, 0)),
disposition: BlockDisposition::Below,
height: 1,
render: Arc::new(|_| div().render_once()),
render: Arc::new(|_| div().into_any()),
}],
Some(Autoscroll::fit()),
cx,

View File

@ -490,6 +490,7 @@ impl EditorElement {
for (ix, fold_indicator) in layout.fold_indicators.drain(..).enumerate() {
if let Some(mut fold_indicator) = fold_indicator {
let mut fold_indicator = fold_indicator.render_into_any();
let available_space = size(
AvailableSpace::MinContent,
AvailableSpace::Definite(line_height * 0.55),
@ -509,20 +510,21 @@ impl EditorElement {
}
}
if let Some(mut indicator) = layout.code_actions_indicator.take() {
if let Some(indicator) = layout.code_actions_indicator.take() {
let mut button = indicator.button.render_into_any();
let available_space = size(
AvailableSpace::MinContent,
AvailableSpace::Definite(line_height),
);
let indicator_size = indicator.element.measure(available_space, editor, cx);
let indicator_size = button.measure(available_space, editor, cx);
let mut x = Pixels::ZERO;
let mut y = indicator.row as f32 * line_height - scroll_top;
// Center indicator.
x += ((layout.gutter_padding + layout.gutter_margin) - indicator_size.width) / 2.;
y += (line_height - indicator_size.height) / 2.;
indicator
.element
.draw(bounds.origin + point(x, y), available_space, editor, cx);
button.draw(bounds.origin + point(x, y), available_space, editor, cx);
}
}
@ -1810,7 +1812,7 @@ impl EditorElement {
.render_code_actions_indicator(&style, active, cx)
.map(|element| CodeActionsIndicator {
row: newest_selection_head.row(),
element,
button: element,
});
}
}
@ -2041,14 +2043,19 @@ impl EditorElement {
// Can't use .and_then() because `.file_name()` and `.parent()` return references :(
if let Some(path) = path {
filename = path.file_name().map(|f| f.to_string_lossy().to_string());
parent_path =
path.parent().map(|p| p.to_string_lossy().to_string() + "/");
parent_path = path
.parent()
.map(|p| SharedString::from(p.to_string_lossy().to_string() + "/"));
}
h_stack()
.size_full()
.bg(gpui::red())
.child(filename.unwrap_or_else(|| "untitled".to_string()))
.child(
filename
.map(SharedString::from)
.unwrap_or_else(|| "untitled".into()),
)
.children(parent_path)
.children(jump_icon) // .p_x(gutter_padding)
} else {
@ -2059,7 +2066,7 @@ impl EditorElement {
.child("")
.children(jump_icon) // .p_x(gutter_padding)
};
element.render()
element.into_any()
}
};
@ -2391,10 +2398,6 @@ enum Invisible {
impl Element<Editor> for EditorElement {
type State = ();
fn element_id(&self) -> Option<gpui::ElementId> {
Some(self.editor_id.into())
}
fn layout(
&mut self,
editor: &mut Editor,
@ -2469,6 +2472,10 @@ impl Element<Editor> for EditorElement {
impl RenderOnce<Editor> for EditorElement {
type Element = Self;
fn element_id(&self) -> Option<gpui::ElementId> {
Some(self.editor_id.into())
}
fn render_once(self) -> Self::Element {
self
}
@ -3098,14 +3105,14 @@ pub struct LayoutState {
context_menu: Option<(DisplayPoint, AnyElement<Editor>)>,
code_actions_indicator: Option<CodeActionsIndicator>,
// hover_popovers: Option<(DisplayPoint, Vec<AnyElement<Editor>>)>,
fold_indicators: Vec<Option<AnyElement<Editor>>>,
fold_indicators: Vec<Option<IconButton<Editor>>>,
tab_invisible: ShapedLine,
space_invisible: ShapedLine,
}
struct CodeActionsIndicator {
row: u32,
element: AnyElement<Editor>,
button: IconButton<Editor>,
}
struct PositionMap {

View File

@ -2,9 +2,8 @@ use collections::HashMap;
use editor::{scroll::autoscroll::Autoscroll, Bias, Editor};
use fuzzy::{CharBag, PathMatch, PathMatchCandidate};
use gpui::{
actions, div, AppContext, Component, Dismiss, Div, FocusHandle, InteractiveElement,
ManagedView, Model, ParentElement, Render, Styled, Task, View, ViewContext, VisualContext,
WeakView,
actions, div, AppContext, Dismiss, Div, FocusHandle, InteractiveElement, ManagedView, Model,
ParentElement, Render, RenderOnce, Styled, Task, View, ViewContext, VisualContext, WeakView,
};
use picker::{Picker, PickerDelegate};
use project::{PathMatchCandidateSet, Project, ProjectPath, WorktreeId};
@ -116,7 +115,7 @@ impl ManagedView for FileFinder {
self.picker.focus_handle(cx)
}
}
impl Render for FileFinder {
impl Render<Self> for FileFinder {
type Element = Div<Self>;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {

View File

@ -143,7 +143,7 @@ impl GoToLine {
}
}
impl Render for GoToLine {
impl Render<Self> for GoToLine {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {

View File

@ -14,12 +14,50 @@ pub trait Render<V: 'static>: 'static + Sized {
pub trait RenderOnce<V: 'static>: Sized {
type Element: Element<V> + 'static;
fn element_id(&self) -> Option<ElementId>;
fn render_once(self) -> Self::Element;
fn render_into_any(self) -> AnyElement<V> {
self.render_once().into_any()
}
fn draw<T, R>(
self,
origin: Point<Pixels>,
available_space: Size<T>,
view_state: &mut V,
cx: &mut ViewContext<V>,
f: impl FnOnce(&mut <Self::Element as Element<V>>::State, &mut ViewContext<V>) -> R,
) -> R
where
T: Clone + Default + Debug + Into<AvailableSpace>,
{
let element = self.render_once();
let element_id = element.element_id();
let element = DrawableElement {
element: Some(element),
phase: ElementDrawPhase::Start,
};
let frame_state = DrawableElement::draw(
element,
origin,
available_space.map(Into::into),
view_state,
cx,
);
if let Some(mut frame_state) = frame_state {
f(&mut frame_state, cx)
} else {
cx.with_element_state(element_id.unwrap(), |element_state, cx| {
let mut element_state = element_state.unwrap();
let result = f(&mut element_state, cx);
(result, element_state)
})
}
}
fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
where
Self: Sized,
@ -52,8 +90,6 @@ pub trait RenderOnce<V: 'static>: Sized {
pub trait Element<V: 'static>: 'static + RenderOnce<V> {
type State: 'static;
fn element_id(&self) -> Option<ElementId>;
fn layout(
&mut self,
view_state: &mut V,
@ -72,35 +108,6 @@ pub trait Element<V: 'static>: 'static + RenderOnce<V> {
fn into_any(self) -> AnyElement<V> {
AnyElement::new(self)
}
fn draw<T, R>(
self,
origin: Point<Pixels>,
available_space: Size<T>,
view_state: &mut V,
cx: &mut ViewContext<V>,
f: impl FnOnce(&mut Self::State, &mut ViewContext<V>) -> R,
) -> R
where
T: Clone + Default + Debug + Into<AvailableSpace>,
{
let element_id = self.element_id();
let element = DrawableElement {
element: Some(self),
phase: ElementDrawPhase::Start,
};
let frame_state = element.draw(origin, available_space.map(Into::into), view_state, cx);
if let Some(mut frame_state) = frame_state {
f(&mut frame_state, cx)
} else {
cx.with_element_state(element_id.unwrap(), |element_state, cx| {
let mut element_state = element_state.unwrap();
let result = f(&mut element_state, cx);
(result, element_state)
})
}
}
}
pub trait Component<V: 'static>: 'static {
@ -131,10 +138,6 @@ impl<V, C> CompositeElement<V, C> {
impl<V: 'static, C: Component<V>> Element<V> for CompositeElement<V, C> {
type State = CompositeElementState<V, C>;
fn element_id(&self) -> Option<ElementId> {
None
}
fn layout(
&mut self,
view: &mut V,
@ -174,6 +177,10 @@ impl<V: 'static, C: Component<V>> Element<V> for CompositeElement<V, C> {
impl<V: 'static, C: Component<V>> RenderOnce<V> for CompositeElement<V, C> {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
None
}
fn render_once(self) -> Self::Element {
self
}
@ -231,23 +238,21 @@ pub struct DrawableElement<V: 'static, E: Element<V>> {
}
#[derive(Default)]
enum ElementDrawPhase<V> {
enum ElementDrawPhase<S> {
#[default]
Start,
LayoutRequested {
layout_id: LayoutId,
frame_state: Option<V>,
frame_state: Option<S>,
},
LayoutComputed {
layout_id: LayoutId,
available_space: Size<AvailableSpace>,
frame_state: Option<V>,
frame_state: Option<S>,
},
}
/// 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<E::State> for
/// improved usability.
/// A wrapper around an implementer of [Element] that allows it to be drawn in a window.
impl<V, E: Element<V>> DrawableElement<V, E> {
fn new(element: E) -> Self {
DrawableElement {
@ -379,6 +384,41 @@ impl<V, E: Element<V>> DrawableElement<V, E> {
}
}
// impl<V: 'static, E: Element<V>> Element<V> for DrawableElement<V, E> {
// type State = <E::Element as Element<V>>::State;
// fn layout(
// &mut self,
// view_state: &mut V,
// element_state: Option<Self::State>,
// cx: &mut ViewContext<V>,
// ) -> (LayoutId, Self::State) {
// }
// fn paint(
// self,
// bounds: Bounds<Pixels>,
// view_state: &mut V,
// element_state: &mut Self::State,
// cx: &mut ViewContext<V>,
// ) {
// todo!()
// }
// }
// impl<V: 'static, E: 'static + Element<V>> RenderOnce<V> for DrawableElement<V, E> {
// type Element = Self;
// fn element_id(&self) -> Option<ElementId> {
// self.element.as_ref()?.element_id()
// }
// fn render_once(self) -> Self::Element {
// self
// }
// }
impl<V, E> ElementObject<V> for Option<DrawableElement<V, E>>
where
E: Element<V>,
@ -476,10 +516,6 @@ impl<V: 'static> AnyElement<V> {
impl<V: 'static> Element<V> for AnyElement<V> {
type State = ();
fn element_id(&self) -> Option<ElementId> {
AnyElement::element_id(self)
}
fn layout(
&mut self,
view_state: &mut V,
@ -504,6 +540,10 @@ impl<V: 'static> Element<V> for AnyElement<V> {
impl<V: 'static> RenderOnce<V> for AnyElement<V> {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
AnyElement::element_id(self)
}
fn render_once(self) -> Self::Element {
self
}

View File

@ -602,10 +602,6 @@ impl<V: 'static> ParentElement<V> for Div<V> {
impl<V: 'static> Element<V> for Div<V> {
type State = DivState;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn layout(
&mut self,
view_state: &mut V,
@ -694,6 +690,10 @@ impl<V: 'static> Element<V> for Div<V> {
impl<V: 'static> RenderOnce<V> for Div<V> {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn render_once(self) -> Self::Element {
self
}
@ -1293,10 +1293,6 @@ where
{
type State = E::State;
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn layout(
&mut self,
view_state: &mut V,
@ -1324,6 +1320,10 @@ where
{
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn render_once(self) -> Self::Element {
self
}
@ -1381,10 +1381,6 @@ where
{
type State = E::State;
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn layout(
&mut self,
view_state: &mut V,
@ -1412,6 +1408,10 @@ where
{
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn render_once(self) -> Self::Element {
self
}

View File

@ -37,10 +37,6 @@ where
impl<V> Element<V> for Img<V> {
type State = InteractiveElementState;
fn element_id(&self) -> Option<crate::ElementId> {
self.interactivity.element_id.clone()
}
fn layout(
&mut self,
_view_state: &mut V,
@ -98,6 +94,10 @@ impl<V> Element<V> for Img<V> {
impl<V: 'static> RenderOnce<V> for Img<V> {
type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
self.interactivity.element_id.clone()
}
fn render_once(self) -> Self::Element {
self
}

View File

@ -60,10 +60,6 @@ impl<V: 'static> ParentElement<V> for Overlay<V> {
impl<V: 'static> Element<V> for Overlay<V> {
type State = OverlayState;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn layout(
&mut self,
view_state: &mut V,
@ -160,6 +156,10 @@ impl<V: 'static> Element<V> for Overlay<V> {
impl<V: 'static> RenderOnce<V> for Overlay<V> {
type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn render_once(self) -> Self::Element {
self
}

View File

@ -26,10 +26,6 @@ impl<V> Svg<V> {
impl<V> Element<V> for Svg<V> {
type State = InteractiveElementState;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn layout(
&mut self,
_view_state: &mut V,
@ -62,6 +58,10 @@ impl<V> Element<V> for Svg<V> {
impl<V: 'static> RenderOnce<V> for Svg<V> {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn render_once(self) -> Self::Element {
self
}

View File

@ -11,10 +11,6 @@ use util::ResultExt;
impl<V: 'static> Element<V> for &'static str {
type State = TextState;
fn element_id(&self) -> Option<ElementId> {
None
}
fn layout(
&mut self,
_: &mut V,
@ -40,6 +36,10 @@ impl<V: 'static> Element<V> for &'static str {
impl<V: 'static> RenderOnce<V> for &'static str {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
None
}
fn render_once(self) -> Self::Element {
self
}
@ -48,10 +48,6 @@ impl<V: 'static> RenderOnce<V> for &'static str {
impl<V: 'static> Element<V> for SharedString {
type State = TextState;
fn element_id(&self) -> Option<ElementId> {
Some(self.clone().into())
}
fn layout(
&mut self,
_: &mut V,
@ -78,6 +74,10 @@ impl<V: 'static> Element<V> for SharedString {
impl<V: 'static> RenderOnce<V> for SharedString {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
Some(self.clone().into())
}
fn render_once(self) -> Self::Element {
self
}
@ -105,10 +105,6 @@ impl StyledText {
impl<V: 'static> Element<V> for StyledText {
type State = TextState;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn layout(
&mut self,
_view: &mut V,
@ -194,6 +190,10 @@ impl<V: 'static> Element<V> for StyledText {
impl<V: 'static> RenderOnce<V> for StyledText {
type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn render_once(self) -> Self::Element {
self
}
@ -300,10 +300,6 @@ struct InteractiveTextState {
impl<V: 'static> Element<V> for InteractiveText {
type State = InteractiveTextState;
fn element_id(&self) -> Option<ElementId> {
Some(self.id.clone())
}
fn layout(
&mut self,
view_state: &mut V,
@ -346,6 +342,10 @@ impl<V: 'static> Element<V> for InteractiveText {
impl<V: 'static> RenderOnce<V> for InteractiveText {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
Some(self.id.clone())
}
fn render_once(self) -> Self::Element {
self
}

View File

@ -104,10 +104,6 @@ pub struct UniformListState {
impl<V: 'static> Element<V> for UniformList<V> {
type State = UniformListState;
fn element_id(&self) -> Option<crate::ElementId> {
Some(self.id.clone())
}
fn layout(
&mut self,
view_state: &mut V,
@ -255,6 +251,10 @@ impl<V: 'static> Element<V> for UniformList<V> {
impl<V> RenderOnce<V> for UniformList<V> {
type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
Some(self.id.clone())
}
fn render_once(self) -> Self::Element {
self
}

View File

@ -208,10 +208,6 @@ impl<V: 'static + Render<V>> From<View<V>> for AnyView {
impl<V: 'static + Render<V>, ParentV: 'static> Element<ParentV> for View<V> {
type State = Option<AnyElement<V>>;
fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into())
}
fn layout(
&mut self,
_parent_view: &mut ParentV,
@ -241,6 +237,10 @@ impl<V: 'static + Render<V>, ParentV: 'static> Element<ParentV> for View<V> {
impl<V: 'static + Render<V>, ParentV: 'static> RenderOnce<ParentV> for View<V> {
type Element = View<V>;
fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into())
}
fn render_once(self) -> Self::Element {
self
}
@ -249,10 +249,6 @@ impl<V: 'static + Render<V>, ParentV: 'static> RenderOnce<ParentV> for View<V> {
impl<V: 'static> Element<V> for AnyView {
type State = Option<Box<dyn Any>>;
fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into())
}
fn layout(
&mut self,
_view_state: &mut V,
@ -277,6 +273,10 @@ impl<V: 'static> Element<V> for AnyView {
impl<ParentV: 'static> RenderOnce<ParentV> for AnyView {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into())
}
fn render_once(self) -> Self::Element {
self
}
@ -334,10 +334,6 @@ where
{
type State = Option<AnyElement<V>>;
fn element_id(&self) -> Option<ElementId> {
Some(self.view.entity_id().into())
}
fn layout(
&mut self,
_: &mut ParentV,
@ -371,6 +367,10 @@ where
{
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.element.as_ref().unwrap().element_id()
}
fn render_once(self) -> Self::Element {
self
}

View File

@ -33,6 +33,10 @@ pub fn derive_render_once(input: TokenStream) -> TokenStream {
{
type Element = gpui::CompositeElement<#view_type, Self>;
fn element_id(&self) -> Option<ElementId> {
None
}
fn render_once(self) -> Self::Element {
gpui::CompositeElement::new(self)
}

View File

@ -1,7 +1,7 @@
use editor::Editor;
use gpui::{
div, prelude::*, uniform_list, AppContext, Component, Div, FocusHandle, FocusableView,
MouseButton, Render, Task, UniformListScrollHandle, View, ViewContext, WindowContext,
div, prelude::*, uniform_list, AppContext, Div, FocusHandle, FocusableView, MouseButton,
Render, Task, UniformListScrollHandle, View, ViewContext, WindowContext,
};
use std::{cmp, sync::Arc};
use ui::{prelude::*, v_stack, Divider, Label, TextColor};
@ -15,7 +15,7 @@ pub struct Picker<D: PickerDelegate> {
}
pub trait PickerDelegate: Sized + 'static {
type ListItem: Component<Picker<Self>>;
type ListItem: RenderOnce<Picker<Self>>;
fn match_count(&self) -> usize;
fn selected_index(&self) -> usize;
@ -180,7 +180,7 @@ impl<D: PickerDelegate> Picker<D> {
}
}
impl<D: PickerDelegate> Render for Picker<D> {
impl<D: PickerDelegate> Render<Self> for Picker<D> {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {

View File

@ -9,9 +9,9 @@ use file_associations::FileAssociations;
use anyhow::{anyhow, Result};
use gpui::{
actions, div, px, uniform_list, Action, AppContext, AssetSource, AsyncWindowContext,
ClipboardItem, Component, Div, EventEmitter, FocusHandle, Focusable, FocusableView,
InteractiveElement, Model, MouseButton, ParentElement, Pixels, Point, PromptLevel, Render,
Stateful, StatefulInteractiveElement, Styled, Task, UniformListScrollHandle, View, ViewContext,
ClipboardItem, Div, EventEmitter, FocusHandle, Focusable, FocusableView, InteractiveElement,
Model, MouseButton, ParentElement, Pixels, Point, PromptLevel, Render, RenderOnce, Stateful,
StatefulInteractiveElement, Styled, Task, UniformListScrollHandle, View, ViewContext,
VisualContext as _, WeakView, WindowContext,
};
use menu::{Confirm, SelectNext, SelectPrev};
@ -1423,7 +1423,7 @@ impl ProjectPanel {
}
}
impl Render for ProjectPanel {
impl Render<Self> for ProjectPanel {
type Element = Focusable<Self, Stateful<Self, Div<Self>>>;
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> Self::Element {

View File

@ -5,7 +5,7 @@ use ui::prelude::*;
pub struct ColorsStory;
impl Render for ColorsStory {
impl Render<Self> for ColorsStory {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
@ -28,7 +28,7 @@ impl Render for ColorsStory {
div()
.w(px(75.))
.line_height(px(24.))
.child(scale.name().to_string()),
.child(scale.name().clone()),
)
.child(
div()

View File

@ -26,7 +26,7 @@ impl FocusStory {
}
}
impl Render for FocusStory {
impl Render<Self> for FocusStory {
type Element = Focusable<Self, Stateful<Self, Div<Self>>>;
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {

View File

@ -11,7 +11,7 @@ impl KitchenSinkStory {
}
}
impl Render for KitchenSinkStory {
impl Render<Self> for KitchenSinkStory {
type Element = Stateful<Self, Div<Self>>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {

View File

@ -1,5 +1,7 @@
use fuzzy::StringMatchCandidate;
use gpui::{div, prelude::*, Div, KeyBinding, Render, Styled, Task, View, WindowContext};
use gpui::{
div, prelude::*, Div, KeyBinding, Render, SharedString, Styled, Task, View, WindowContext,
};
use picker::{Picker, PickerDelegate};
use std::sync::Arc;
use theme2::ActiveTheme;
@ -54,7 +56,8 @@ impl PickerDelegate for Delegate {
let Some(candidate_ix) = self.matches.get(ix) else {
return div();
};
let candidate = self.candidates[*candidate_ix].string.clone();
// TASK: Make StringMatchCandidate::string a SharedString
let candidate = SharedString::from(self.candidates[*candidate_ix].string.clone());
div()
.text_color(colors.text)
@ -202,7 +205,7 @@ impl PickerStory {
}
}
impl Render for PickerStory {
impl Render<Self> for PickerStory {
type Element = Div<Self>;
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {

View File

@ -10,7 +10,7 @@ impl ScrollStory {
}
}
impl Render for ScrollStory {
impl Render<Self> for ScrollStory {
type Element = Stateful<Self, Div<Self>>;
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {

View File

@ -1,6 +1,4 @@
use gpui::{
div, white, Div, ParentElement, Render, Styled, View, VisualContext, WindowContext,
};
use gpui::{div, white, Div, ParentElement, Render, Styled, View, VisualContext, WindowContext};
pub struct TextStory;
@ -10,7 +8,7 @@ impl TextStory {
}
}
impl Render for TextStory {
impl Render<Self> for TextStory {
type Element = Div<Self>;
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {

View File

@ -1,4 +1,4 @@
use gpui::{px, rgb, Div, Hsla, Render};
use gpui::{px, rgb, Div, Hsla, Render, RenderOnce};
use ui::prelude::*;
use crate::story::Story;
@ -7,7 +7,7 @@ use crate::story::Story;
/// [https://developer.mozilla.org/en-US/docs/Web/CSS/z-index](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index).
pub struct ZIndexStory;
impl Render for ZIndexStory {
impl Render<Self> for ZIndexStory {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
@ -79,17 +79,15 @@ trait Styles: Styled + Sized {
impl<V: 'static> Styles for Div<V> {}
// #[derive(RenderOnce)]
#[derive(RenderOnce)]
struct ZIndexExample {
z_index: u32,
}
impl ZIndexExample {
pub fn new(z_index: u32) -> Self {
Self { z_index }
}
impl<V: 'static> Component<V> for ZIndexExample {
type Rendered = Div<V>;
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
div()
.relative()
.size_full()
@ -109,14 +107,14 @@ impl ZIndexExample {
// HACK: Simulate `text-align: center`.
.pl(px(24.))
.z_index(self.z_index)
.child(format!(
.child(SharedString::from(format!(
"z-index: {}",
if self.z_index == 0 {
"auto".to_string()
} else {
self.z_index.to_string()
}
)),
))),
)
// Blue blocks.
.child(
@ -173,3 +171,9 @@ impl ZIndexExample {
)
}
}
impl ZIndexExample {
pub fn new(z_index: u32) -> Self {
Self { z_index }
}
}

View File

@ -105,7 +105,7 @@ impl StoryWrapper {
}
}
impl Render for StoryWrapper {
impl Render<Self> for StoryWrapper {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {

View File

@ -335,7 +335,7 @@ impl TerminalPanel {
impl EventEmitter<PanelEvent> for TerminalPanel {}
impl Render for TerminalPanel {
impl Render<Self> for TerminalPanel {
type Element = Div<Self>;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {

View File

@ -9,7 +9,7 @@ pub mod terminal_panel;
// use crate::terminal_element::TerminalElement;
use editor::{scroll::autoscroll::Autoscroll, Editor};
use gpui::{
actions, div, img, red, Action, AnyElement, AppContext, Component, DispatchPhase, Div,
actions, div, img, red, Action, AnyElement, AppContext, DispatchPhase, Div, Element,
EventEmitter, FocusEvent, FocusHandle, Focusable, FocusableElement, FocusableView,
InputHandler, InteractiveElement, KeyDownEvent, Keystroke, Model, MouseButton, ParentElement,
Pixels, Render, SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView,
@ -538,7 +538,7 @@ impl TerminalView {
}
}
impl Render for TerminalView {
impl Render<Self> for TerminalView {
type Element = Focusable<Self, Div<Self>>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
@ -578,7 +578,7 @@ impl Render for TerminalView {
.children(
self.context_menu
.clone()
.map(|context_menu| div().z_index(1).absolute().child(context_menu.render())),
.map(|context_menu| div().z_index(1).absolute().child(context_menu)),
)
.track_focus(&self.focus_handle)
.on_focus_in(Self::focus_in)
@ -756,8 +756,8 @@ impl Item for TerminalView {
div()
.child(img().uri("icons/terminal.svg").bg(red()))
.child(title)
.render()
.child(SharedString::from(title))
.into_any()
}
fn clone_on_split(

View File

@ -78,7 +78,7 @@ impl Render<Self> for ContextMenu {
}
pub struct MenuHandle<V: 'static, M: ManagedView> {
id: Option<ElementId>,
id: ElementId,
child_builder: Option<Box<dyn FnOnce(bool) -> AnyElement<V> + 'static>>,
menu_builder: Option<Rc<dyn Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static>>,
@ -87,11 +87,6 @@ pub struct MenuHandle<V: 'static, M: ManagedView> {
}
impl<V: 'static, M: ManagedView> MenuHandle<V, M> {
pub fn id(mut self, id: impl Into<ElementId>) -> Self {
self.id = Some(id.into());
self
}
pub fn menu(mut self, f: impl Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static) -> Self {
self.menu_builder = Some(Rc::new(f));
self
@ -116,9 +111,9 @@ impl<V: 'static, M: ManagedView> MenuHandle<V, M> {
}
}
pub fn menu_handle<V: 'static, M: ManagedView>() -> MenuHandle<V, M> {
pub fn menu_handle<V: 'static, M: ManagedView>(id: impl Into<ElementId>) -> MenuHandle<V, M> {
MenuHandle {
id: None,
id: id.into(),
child_builder: None,
menu_builder: None,
anchor: None,
@ -136,10 +131,6 @@ pub struct MenuHandleState<V, M> {
impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
type State = MenuHandleState<V, M>;
fn element_id(&self) -> Option<gpui::ElementId> {
Some(self.id.clone().expect("menu_handle must have an id()"))
}
fn layout(
&mut self,
view_state: &mut V,
@ -251,6 +242,10 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
impl<V: 'static, M: ManagedView> RenderOnce<V> for MenuHandle<V, M> {
type Element = Self;
fn element_id(&self) -> Option<gpui::ElementId> {
Some(self.id.clone())
}
fn render_once(self) -> Self::Element {
self
}
@ -297,8 +292,7 @@ mod stories {
.flex_col()
.justify_between()
.child(
menu_handle()
.id("test2")
menu_handle("test2")
.child(|is_open| {
Label::new(if is_open {
"TOP LEFT"
@ -309,8 +303,7 @@ mod stories {
.menu(move |_, cx| build_menu(cx, "top left")),
)
.child(
menu_handle()
.id("test1")
menu_handle("test1")
.child(|is_open| {
Label::new(if is_open {
"BOTTOM LEFT"
@ -329,8 +322,7 @@ mod stories {
.flex_col()
.justify_between()
.child(
menu_handle()
.id("test3")
menu_handle("test3")
.child(|is_open| {
Label::new(if is_open {
"TOP RIGHT"
@ -342,8 +334,7 @@ mod stories {
.menu(move |_, cx| build_menu(cx, "top right")),
)
.child(
menu_handle()
.id("test4")
menu_handle("test4")
.child(|is_open| {
Label::new(if is_open {
"BOTTOM RIGHT"

View File

@ -1,4 +1,4 @@
use gpui::RenderOnce;
use gpui::{Div, RenderOnce};
use crate::prelude::*;
@ -7,12 +7,29 @@ enum DividerDirection {
Vertical,
}
// #[derive(RenderOnce)]
#[derive(RenderOnce)]
pub struct Divider {
direction: DividerDirection,
inset: bool,
}
impl<V: 'static> Component<V> for Divider {
type Rendered = Div<V>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
div()
.map(|this| match self.direction {
DividerDirection::Horizontal => {
this.h_px().w_full().when(self.inset, |this| this.mx_1p5())
}
DividerDirection::Vertical => {
this.w_px().h_full().when(self.inset, |this| this.my_1p5())
}
})
.bg(cx.theme().colors().border_variant)
}
}
impl Divider {
pub fn horizontal() -> Self {
Self {

View File

@ -1,8 +1,8 @@
use crate::{status_bar::StatusItemView, Axis, Workspace};
use gpui::{
div, px, Action, AnchorCorner, AnyView, AppContext, Component, Div, Entity, EntityId,
EventEmitter, FocusHandle, FocusableView, ParentElement, Render, RenderOnce, SharedString,
Styled, Subscription, View, ViewContext, VisualContext, WeakView, WindowContext,
div, px, Action, AnchorCorner, AnyView, AppContext, Div, Entity, EntityId, EventEmitter,
FocusHandle, FocusableView, ParentElement, Render, RenderOnce, SharedString, Styled,
Subscription, View, ViewContext, VisualContext, WeakView, WindowContext,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@ -653,8 +653,7 @@ impl Render<Self> for PanelButtons {
};
Some(
menu_handle()
.id(name)
menu_handle(name)
.menu(move |_, cx| {
cx.build_view(|cx| ContextMenu::new(cx).header("SECTION"))
})

View File

@ -7,9 +7,9 @@ use crate::{
use anyhow::Result;
use collections::{HashMap, HashSet, VecDeque};
use gpui::{
actions, prelude::*, Action, AppContext, AsyncWindowContext, Component, Div, EntityId,
EventEmitter, FocusHandle, Focusable, FocusableView, Model, Pixels, Point, PromptLevel, Render,
Task, View, ViewContext, VisualContext, WeakView, WindowContext,
actions, prelude::*, Action, AppContext, AsyncWindowContext, Div, EntityId, EventEmitter,
FocusHandle, Focusable, FocusableView, Model, Pixels, Point, PromptLevel, Render, Task, View,
ViewContext, VisualContext, WeakView, WindowContext,
};
use parking_lot::Mutex;
use project2::{Project, ProjectEntryId, ProjectPath};

View File

@ -7,8 +7,7 @@ use db2::sqlez::{
statement::Statement,
};
use gpui::{
point, size, AnyElement, AnyWeakView, Bounds, Div, Model, Pixels, Point, RenderOnce, View,
ViewContext,
point, size, AnyWeakView, Bounds, Div, Model, Pixels, Point, RenderOnce, View, ViewContext,
};
use parking_lot::Mutex;
use project2::Project;

View File

@ -2,8 +2,8 @@ use std::any::TypeId;
use crate::{ItemHandle, Pane};
use gpui::{
div, AnyView, Component, Div, ParentElement, Render, RenderOnce, Styled, Subscription, View,
ViewContext, WindowContext,
div, AnyView, Div, ParentElement, Render, RenderOnce, Styled, Subscription, View, ViewContext,
WindowContext,
};
use theme2::ActiveTheme;
use ui::h_stack;