mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
WIP
This commit is contained in:
parent
19e4cad7a9
commit
54a7419fa2
9
Cargo.lock
generated
9
Cargo.lock
generated
@ -3041,6 +3041,7 @@ dependencies = [
|
||||
name = "gpui_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
@ -5043,9 +5044,17 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"gpui",
|
||||
"log",
|
||||
"playground_ui",
|
||||
"simplelog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "playground_ui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gpui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.5.0"
|
||||
|
@ -29,6 +29,7 @@ members = [
|
||||
"crates/go_to_line",
|
||||
"crates/gpui",
|
||||
"crates/gpui/playground",
|
||||
"crates/gpui/playground/ui",
|
||||
"crates/gpui_macros",
|
||||
"crates/install_cli",
|
||||
"crates/journal",
|
||||
|
@ -8,6 +8,8 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
playground_ui = { path = "ui" }
|
||||
|
||||
gpui = { path = ".." }
|
||||
log.workspace = true
|
||||
simplelog = "0.9"
|
||||
|
@ -1,52 +1,45 @@
|
||||
use elements::{Length, Node, NodeStyle};
|
||||
use gpui::{color::Color, AnyElement, Element, Entity, View, ViewContext};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use gpui::{AnyElement, Element, Entity, View};
|
||||
use log::LevelFilter;
|
||||
use simplelog::SimpleLogger;
|
||||
|
||||
mod elements;
|
||||
|
||||
fn main() {
|
||||
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
|
||||
|
||||
gpui::App::new(()).unwrap().run(|cx| {
|
||||
cx.platform().activate(true);
|
||||
cx.add_window(Default::default(), |_| PlaygroundView);
|
||||
cx.add_window(Default::default(), |_| Playground::default());
|
||||
});
|
||||
}
|
||||
|
||||
struct PlaygroundView;
|
||||
#[derive(Clone, Default)]
|
||||
struct Playground(playground_ui::Playground);
|
||||
|
||||
impl Entity for PlaygroundView {
|
||||
impl Deref for Playground {
|
||||
type Target = playground_ui::Playground;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Playground {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity for Playground {
|
||||
type Event = ();
|
||||
}
|
||||
|
||||
impl View for PlaygroundView {
|
||||
impl View for Playground {
|
||||
fn ui_name() -> &'static str {
|
||||
"PlaygroundView"
|
||||
}
|
||||
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> AnyElement<PlaygroundView> {
|
||||
// Node::with_style(NodeStyle)
|
||||
// Node::new().width(100.0).fill(Color::red())
|
||||
//
|
||||
Node::new()
|
||||
.width(Length::auto(1.))
|
||||
.fill(Color::red())
|
||||
.row()
|
||||
.children([
|
||||
Node::new().width(20.).height(20.).fill(Color::green()),
|
||||
Node::new().width(20.).height(20.).fill(Color::blue()),
|
||||
Node::new().width(30.).height(30.).fill(Color::yellow()),
|
||||
Node::new().width(50.).height(50.).fill(Color::yellow()),
|
||||
])
|
||||
.into_any()
|
||||
|
||||
// Node::with_style(
|
||||
// NodeStyle::default()
|
||||
// .width(100.)
|
||||
// .height(100.)
|
||||
// .fill(Color::red()),
|
||||
// )
|
||||
// .into_any()
|
||||
fn render(&mut self, _: &mut gpui::ViewContext<Self>) -> AnyElement<Playground> {
|
||||
self.0.clone().into_any()
|
||||
}
|
||||
}
|
||||
|
12
crates/gpui/playground/ui/Cargo.toml
Normal file
12
crates/gpui/playground/ui/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "playground_ui"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "playground_ui"
|
||||
path = "src/playground_ui.rs"
|
||||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
gpui = { path = "../.." }
|
91
crates/gpui/playground/ui/src/playground_ui.rs
Normal file
91
crates/gpui/playground/ui/src/playground_ui.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use gpui::{
|
||||
elements::{
|
||||
node::{column, length::auto, row},
|
||||
Text,
|
||||
},
|
||||
AnyElement, Element, View, ViewContext,
|
||||
};
|
||||
use std::{borrow::Cow, marker::PhantomData};
|
||||
use tokens::{margin::m4, text::lg};
|
||||
|
||||
mod tokens;
|
||||
|
||||
#[derive(Element, Clone, Default)]
|
||||
pub struct Playground;
|
||||
|
||||
impl Playground {
|
||||
pub fn render<V: View>(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> AnyElement<V> {
|
||||
column()
|
||||
.width(auto())
|
||||
.child(dialog(
|
||||
"This is a dialog",
|
||||
"You would see a description here.",
|
||||
))
|
||||
.into_any()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DialogDelegate<V: View>: 'static {
|
||||
fn handle_submit<B>(&mut self, view: &mut V, button: B);
|
||||
}
|
||||
|
||||
impl<V: View> DialogDelegate<V> for () {
|
||||
fn handle_submit<B>(&mut self, _: &mut V, _: B) {}
|
||||
}
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct Dialog<V: View, D: DialogDelegate<V>> {
|
||||
title: Cow<'static, str>,
|
||||
description: Cow<'static, str>,
|
||||
delegate: Option<D>,
|
||||
view_type: PhantomData<V>,
|
||||
}
|
||||
|
||||
pub fn dialog<V: View>(
|
||||
title: impl Into<Cow<'static, str>>,
|
||||
description: impl Into<Cow<'static, str>>,
|
||||
) -> Dialog<V, ()> {
|
||||
Dialog {
|
||||
title: title.into(),
|
||||
description: description.into(),
|
||||
delegate: None,
|
||||
view_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View, D: DialogDelegate<V>> Dialog<V, D> {
|
||||
pub fn with_delegate(mut self, delegate: D) -> Dialog<V, D> {
|
||||
let old_delegate = self.delegate.replace(delegate);
|
||||
debug_assert!(old_delegate.is_none(), "delegate already set");
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct Button<V: View, F: FnOnce(&mut V, &mut ViewContext<V>)> {
|
||||
label: Cow<'static, str>,
|
||||
on_click: Option<F>,
|
||||
view_type: PhantomData<V>,
|
||||
}
|
||||
|
||||
fn button<V: View, F: FnOnce(&mut V, &mut ViewContext<V>)>(
|
||||
label: impl Into<Cow<'static, str>>,
|
||||
) -> Button<V, F> {
|
||||
Button {
|
||||
label: label.into(),
|
||||
on_click: None,
|
||||
view_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View, D: DialogDelegate<V>> Dialog<V, D> {
|
||||
pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> AnyElement<V> {
|
||||
column()
|
||||
.child(text(self.title.clone()).text_size(lg()))
|
||||
.child(text(self.description.clone()).margins(m4(), auto()))
|
||||
.child(row().children([
|
||||
button("Cancel").margin_left(auto()),
|
||||
button("OK").margin_left(m4()),
|
||||
]))
|
||||
.into_any()
|
||||
}
|
||||
}
|
157
crates/gpui/playground/ui/src/tokens.rs
Normal file
157
crates/gpui/playground/ui/src/tokens.rs
Normal file
@ -0,0 +1,157 @@
|
||||
pub mod color {
|
||||
use gpui::color::Color;
|
||||
|
||||
pub fn background(elevation: f32) -> Color {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod text {
|
||||
pub fn xs() -> f32 {
|
||||
0.75
|
||||
}
|
||||
|
||||
pub fn sm() -> f32 {
|
||||
0.875
|
||||
}
|
||||
|
||||
pub fn base() -> f32 {
|
||||
1.0
|
||||
}
|
||||
|
||||
pub fn lg() -> f32 {
|
||||
1.125
|
||||
}
|
||||
|
||||
pub fn xl() -> f32 {
|
||||
1.25
|
||||
}
|
||||
|
||||
pub fn xxl() -> f32 {
|
||||
1.5
|
||||
}
|
||||
|
||||
pub fn xxxl() -> f32 {
|
||||
1.875
|
||||
}
|
||||
|
||||
pub fn xxxx() -> f32 {
|
||||
2.25
|
||||
}
|
||||
|
||||
pub fn xxxxx() -> f32 {
|
||||
3.0
|
||||
}
|
||||
|
||||
pub fn xxxxxx() -> f32 {
|
||||
4.0
|
||||
}
|
||||
}
|
||||
|
||||
pub mod padding {
|
||||
pub fn p1() -> f32 {
|
||||
0.25
|
||||
}
|
||||
|
||||
pub fn p2() -> f32 {
|
||||
0.5
|
||||
}
|
||||
|
||||
pub fn p3() -> f32 {
|
||||
0.75
|
||||
}
|
||||
|
||||
pub fn p4() -> f32 {
|
||||
1.0
|
||||
}
|
||||
|
||||
pub fn p5() -> f32 {
|
||||
1.25
|
||||
}
|
||||
|
||||
pub fn p6() -> f32 {
|
||||
1.5
|
||||
}
|
||||
|
||||
pub fn p8() -> f32 {
|
||||
2.0
|
||||
}
|
||||
|
||||
pub fn p10() -> f32 {
|
||||
2.5
|
||||
}
|
||||
|
||||
pub fn p12() -> f32 {
|
||||
3.0
|
||||
}
|
||||
|
||||
pub fn p16() -> f32 {
|
||||
4.0
|
||||
}
|
||||
|
||||
pub fn p20() -> f32 {
|
||||
5.0
|
||||
}
|
||||
|
||||
pub fn p24() -> f32 {
|
||||
6.0
|
||||
}
|
||||
|
||||
pub fn p32() -> f32 {
|
||||
8.0
|
||||
}
|
||||
}
|
||||
|
||||
pub mod margin {
|
||||
pub fn m1() -> f32 {
|
||||
0.25
|
||||
}
|
||||
|
||||
pub fn m2() -> f32 {
|
||||
0.5
|
||||
}
|
||||
|
||||
pub fn m3() -> f32 {
|
||||
0.75
|
||||
}
|
||||
|
||||
pub fn m4() -> f32 {
|
||||
1.0
|
||||
}
|
||||
|
||||
pub fn m5() -> f32 {
|
||||
1.25
|
||||
}
|
||||
|
||||
pub fn m6() -> f32 {
|
||||
1.5
|
||||
}
|
||||
|
||||
pub fn m8() -> f32 {
|
||||
2.0
|
||||
}
|
||||
|
||||
pub fn m10() -> f32 {
|
||||
2.5
|
||||
}
|
||||
|
||||
pub fn m12() -> f32 {
|
||||
3.0
|
||||
}
|
||||
|
||||
pub fn m16() -> f32 {
|
||||
4.0
|
||||
}
|
||||
|
||||
pub fn m20() -> f32 {
|
||||
5.0
|
||||
}
|
||||
|
||||
pub fn m24() -> f32 {
|
||||
6.0
|
||||
}
|
||||
|
||||
pub fn m32() -> f32 {
|
||||
8.0
|
||||
}
|
||||
}
|
@ -17,33 +17,73 @@ use serde_json::json;
|
||||
#[repr(transparent)]
|
||||
pub struct Color(#[schemars(with = "String")] ColorU);
|
||||
|
||||
pub fn color(rgba: u32) -> Color {
|
||||
color(rgba)
|
||||
}
|
||||
|
||||
pub fn rgb(r: f32, g: f32, b: f32) -> Color {
|
||||
Color(ColorF::new(r, g, b, 1.).to_u8())
|
||||
}
|
||||
|
||||
pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Color {
|
||||
Color(ColorF::new(r, g, b, a).to_u8())
|
||||
}
|
||||
|
||||
pub fn transparent_black() -> Color {
|
||||
Color(ColorU::transparent_black())
|
||||
}
|
||||
|
||||
pub fn black() -> Color {
|
||||
Color(ColorU::black())
|
||||
}
|
||||
|
||||
pub fn white() -> Color {
|
||||
Color(ColorU::white())
|
||||
}
|
||||
|
||||
pub fn red() -> Color {
|
||||
color(0xff0000ff)
|
||||
}
|
||||
|
||||
pub fn green() -> Color {
|
||||
color(0x00ff00ff)
|
||||
}
|
||||
|
||||
pub fn blue() -> Color {
|
||||
color(0x0000ffff)
|
||||
}
|
||||
|
||||
pub fn yellow() -> Color {
|
||||
color(0xffff00ff)
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn transparent_black() -> Self {
|
||||
Self(ColorU::transparent_black())
|
||||
transparent_black()
|
||||
}
|
||||
|
||||
pub fn black() -> Self {
|
||||
Self(ColorU::black())
|
||||
black()
|
||||
}
|
||||
|
||||
pub fn white() -> Self {
|
||||
Self(ColorU::white())
|
||||
white()
|
||||
}
|
||||
|
||||
pub fn red() -> Self {
|
||||
Self(ColorU::from_u32(0xff0000ff))
|
||||
Color::from_u32(0xff0000ff)
|
||||
}
|
||||
|
||||
pub fn green() -> Self {
|
||||
Self(ColorU::from_u32(0x00ff00ff))
|
||||
Color::from_u32(0x00ff00ff)
|
||||
}
|
||||
|
||||
pub fn blue() -> Self {
|
||||
Self(ColorU::from_u32(0x0000ffff))
|
||||
Color::from_u32(0x0000ffff)
|
||||
}
|
||||
|
||||
pub fn yellow() -> Self {
|
||||
Self(ColorU::from_u32(0xffff00ff))
|
||||
Color::from_u32(0xffff00ff)
|
||||
}
|
||||
|
||||
pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
|
@ -12,6 +12,7 @@ mod keystroke_label;
|
||||
mod label;
|
||||
mod list;
|
||||
mod mouse_event_handler;
|
||||
pub mod node;
|
||||
mod overlay;
|
||||
mod resizable;
|
||||
mod stack;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use gpui::{
|
||||
use crate::{
|
||||
color::Color,
|
||||
geometry::{
|
||||
rect::RectF,
|
||||
@ -9,47 +9,62 @@ use gpui::{
|
||||
serde_json::Value,
|
||||
AnyElement, Element, LayoutContext, Quad, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use std::{any::Any, f32, ops::Range};
|
||||
use std::{any::Any, borrow::Cow, f32, ops::Range};
|
||||
|
||||
// Core idea is that everything is a channel, and channels are heirarchical.
|
||||
//
|
||||
// Tree 🌲 of channels
|
||||
// - (Potentially v0.2) All channels associated with a conversation (Slack model)
|
||||
// - Audio
|
||||
// - You can share projects into the channel
|
||||
// - 1.
|
||||
//
|
||||
//
|
||||
// - 2 thoughts:
|
||||
// - Difference from where we are to the above:
|
||||
// - Channels = rooms + chat + persistence
|
||||
// - Chat = multiplayer assistant panel + server integrated persistence
|
||||
// - The tree structure, is good for navigating chats, AND it's good for distributing permissions.
|
||||
// #zed-public// /zed- <- Share a pointer (URL) for this
|
||||
//
|
||||
//
|
||||
use self::length::Length;
|
||||
|
||||
pub struct Node<V: View> {
|
||||
style: NodeStyle,
|
||||
children: Vec<AnyElement<V>>,
|
||||
content: Content<V>,
|
||||
}
|
||||
|
||||
enum Content<V: View> {
|
||||
Children(Vec<AnyElement<V>>),
|
||||
Text(Cow<'static, str>),
|
||||
}
|
||||
|
||||
impl<V: View> Default for Content<V> {
|
||||
fn default() -> Self {
|
||||
Self::Children(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn column<V: View>() -> Node<V> {
|
||||
Node::default()
|
||||
}
|
||||
|
||||
pub fn row<V: View>() -> Node<V> {
|
||||
Node {
|
||||
style: NodeStyle {
|
||||
axis: Axis3d::X,
|
||||
..Default::default()
|
||||
},
|
||||
content: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stack<V: View>() -> Node<V> {
|
||||
Node {
|
||||
style: NodeStyle {
|
||||
axis: Axis3d::Z,
|
||||
..Default::default()
|
||||
},
|
||||
content: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> Default for Node<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
style: Default::default(),
|
||||
children: Default::default(),
|
||||
content: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View> Node<V> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn child(mut self, child: impl Element<V>) -> Self {
|
||||
self.children.push(child.into_any());
|
||||
self.content.push(child.into_any());
|
||||
self
|
||||
}
|
||||
|
||||
@ -58,7 +73,7 @@ impl<V: View> Node<V> {
|
||||
I: IntoIterator<Item = E>,
|
||||
E: Element<V>,
|
||||
{
|
||||
self.children
|
||||
self.content
|
||||
.extend(children.into_iter().map(|child| child.into_any()));
|
||||
self
|
||||
}
|
||||
@ -100,7 +115,7 @@ impl<V: View> Node<V> {
|
||||
let mut cross_axis_max: f32 = 0.0;
|
||||
|
||||
// First pass: Layout non-flex children only
|
||||
for child in &mut self.children {
|
||||
for child in &mut self.content {
|
||||
let child_flex = child.metadata::<NodeStyle>().and_then(|style| match axis {
|
||||
Axis2d::X => style.width.flex(),
|
||||
Axis2d::Y => style.height.flex(),
|
||||
@ -138,7 +153,7 @@ impl<V: View> Node<V> {
|
||||
if total_flex > 0. {
|
||||
let space_per_flex = remaining_space.max(0.) / total_flex;
|
||||
|
||||
for child in &mut self.children {
|
||||
for child in &mut self.content {
|
||||
let child_flex = child.metadata::<NodeStyle>().and_then(|style| match axis {
|
||||
Axis2d::X => style.width.flex(),
|
||||
Axis2d::Y => style.height.flex(),
|
||||
@ -209,7 +224,7 @@ impl<V: View> Node<V> {
|
||||
align_vertically,
|
||||
);
|
||||
|
||||
for child in &mut self.children {
|
||||
for child in &mut self.content {
|
||||
// Align each child along the cross axis
|
||||
align_horizontally = !align_horizontally;
|
||||
align_vertically = !align_vertically;
|
||||
@ -400,7 +415,7 @@ impl<V: View> Element<V> for Node<V> {
|
||||
});
|
||||
}
|
||||
|
||||
if !self.children.is_empty() {
|
||||
if !self.content.is_empty() {
|
||||
// Account for padding first.
|
||||
let padding = &self.style.padding;
|
||||
let padded_bounds = RectF::from_points(
|
||||
@ -442,7 +457,7 @@ impl<V: View> Element<V> for Node<V> {
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
self.children
|
||||
self.content
|
||||
.iter()
|
||||
.find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
|
||||
}
|
||||
@ -456,9 +471,10 @@ impl<V: View> Element<V> for Node<V> {
|
||||
cx: &ViewContext<V>,
|
||||
) -> Value {
|
||||
json!({
|
||||
"type": "Cell",
|
||||
"type": "Node",
|
||||
"bounds": bounds.to_json(),
|
||||
"children": self.children.iter().map(|child| child.debug(view, cx)).collect::<Vec<Value>>()
|
||||
// TODO!
|
||||
// "children": self.content.iter().map(|child| child.debug(view, cx)).collect::<Vec<Value>>()
|
||||
})
|
||||
}
|
||||
|
||||
@ -574,8 +590,9 @@ impl Border {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub enum Length {
|
||||
pub mod length {
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub enum Length {
|
||||
#[default]
|
||||
Hug,
|
||||
Fixed(f32),
|
||||
@ -584,16 +601,19 @@ pub enum Length {
|
||||
min: f32,
|
||||
max: f32,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for Length {
|
||||
impl From<f32> for Length {
|
||||
fn from(value: f32) -> Self {
|
||||
Length::Fixed(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Length {
|
||||
pub fn auto(flex: f32) -> Self {
|
||||
pub fn auto() -> Length {
|
||||
flex(1.)
|
||||
}
|
||||
|
||||
pub fn flex(flex: f32) -> Length {
|
||||
Length::Auto {
|
||||
flex,
|
||||
min: 0.,
|
||||
@ -601,7 +621,7 @@ impl Length {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn auto_constrained(flex: f32, min: Option<f32>, max: Option<f32>) -> Self {
|
||||
pub fn constrained(flex: f32, min: Option<f32>, max: Option<f32>) -> Length {
|
||||
Length::Auto {
|
||||
flex,
|
||||
min: min.unwrap_or(0.),
|
||||
@ -609,12 +629,14 @@ impl Length {
|
||||
}
|
||||
}
|
||||
|
||||
impl Length {
|
||||
pub fn flex(&self) -> Option<f32> {
|
||||
match self {
|
||||
Length::Auto { flex, .. } => Some(*flex),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
@ -400,6 +400,58 @@ fn layout_highlighted_chunks<'a>(
|
||||
layouts
|
||||
}
|
||||
|
||||
// Need to figure out how fonts flow through the tree to implement this.
|
||||
impl<V: View> Element<V> for Cow<'static, str> {
|
||||
type LayoutState = ();
|
||||
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
view: &mut V,
|
||||
cx: &mut LayoutContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
layout: &mut Self::LayoutState,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn rect_for_text_range(
|
||||
&self,
|
||||
range_utf16: Range<usize>,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
layout: &Self::LayoutState,
|
||||
paint: &Self::PaintState,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn debug(
|
||||
&self,
|
||||
bounds: RectF,
|
||||
layout: &Self::LayoutState,
|
||||
paint: &Self::PaintState,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> crate::serde_json::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -10,7 +10,7 @@ proc-macro = true
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
lazy_static.workspace = true
|
||||
proc-macro2 = "1.0"
|
||||
syn = "1.0"
|
||||
quote = "1.0"
|
||||
proc-macro2 = "1.0"
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Ident;
|
||||
use quote::{format_ident, quote};
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use std::mem;
|
||||
use syn::{
|
||||
parse_macro_input, parse_quote, spanned::Spanned as _, AttributeArgs, DeriveInput, FnArg,
|
||||
ItemFn, Lit, Meta, NestedMeta, Type,
|
||||
GenericParam, Generics, ItemFn, Lit, Meta, NestedMeta, Type, TypeGenerics, TypeParam,
|
||||
WhereClause,
|
||||
};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
@ -278,14 +279,44 @@ fn parse_bool(literal: &Lit) -> Result<bool, TokenStream> {
|
||||
|
||||
#[proc_macro_derive(Element)]
|
||||
pub fn element_derive(input: TokenStream) -> TokenStream {
|
||||
// Parse the input tokens into a syntax tree
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
let type_name = ast.ident;
|
||||
|
||||
// The name of the struct/enum
|
||||
let name = input.ident;
|
||||
let placeholder_view_generics: Generics = parse_quote! { <V: View> };
|
||||
let placeholder_view_type_name: Ident = parse_quote! { V };
|
||||
let view_type_name: Ident;
|
||||
let impl_generics: syn::ImplGenerics<'_>;
|
||||
let type_generics: Option<syn::TypeGenerics<'_>>;
|
||||
let where_clause: Option<&'_ WhereClause>;
|
||||
|
||||
match ast.generics.params.iter().find_map(|param| {
|
||||
if let GenericParam::Type(type_param) = param {
|
||||
Some(type_param.ident.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
Some(type_name) => {
|
||||
view_type_name = type_name;
|
||||
let generics = ast.generics.split_for_impl();
|
||||
impl_generics = generics.0;
|
||||
type_generics = Some(generics.1);
|
||||
where_clause = generics.2;
|
||||
}
|
||||
_ => {
|
||||
view_type_name = placeholder_view_type_name;
|
||||
let generics = placeholder_view_generics.split_for_impl();
|
||||
impl_generics = generics.0;
|
||||
type_generics = None;
|
||||
where_clause = generics.2;
|
||||
}
|
||||
}
|
||||
|
||||
let gen = quote! {
|
||||
impl #impl_generics Element<#view_type_name> for #type_name #type_generics
|
||||
#where_clause
|
||||
{
|
||||
|
||||
let expanded = quote! {
|
||||
impl<V: gpui::View> gpui::elements::Element<V> for #name {
|
||||
type LayoutState = gpui::elements::AnyElement<V>;
|
||||
type PaintState = ();
|
||||
|
||||
@ -337,6 +368,6 @@ pub fn element_derive(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
}
|
||||
};
|
||||
// Return generated code
|
||||
TokenStream::from(expanded)
|
||||
|
||||
gen.into()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user