Mainline GPUI2 UI work (#3079)

This PR mainlines the current state of new GPUI2-based UI from the
`gpui2-ui` branch.

Release Notes:

- N/A

---------

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
Co-authored-by: Nate <nate@zed.dev>
This commit is contained in:
Marshall Bowers 2023-10-02 18:20:47 -04:00 committed by GitHub
parent 08361eb84e
commit 9e1f7c4c18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 1047 additions and 399 deletions

4
Cargo.lock generated
View file

@ -2790,7 +2790,6 @@ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
"log", "log",
"lsp",
"parking_lot 0.11.2", "parking_lot 0.11.2",
"regex", "regex",
"rope", "rope",
@ -7403,6 +7402,8 @@ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
"clap 4.4.4", "clap 4.4.4",
"fs",
"futures 0.3.28",
"gpui2", "gpui2",
"itertools 0.11.0", "itertools 0.11.0",
"log", "log",
@ -8638,6 +8639,7 @@ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
"gpui2", "gpui2",
"rand 0.8.5",
"serde", "serde",
"settings", "settings",
"smallvec", "smallvec",

View file

@ -9,8 +9,6 @@ path = "src/fs.rs"
[dependencies] [dependencies]
collections = { path = "../collections" } collections = { path = "../collections" }
gpui = { path = "../gpui" }
lsp = { path = "../lsp" }
rope = { path = "../rope" } rope = { path = "../rope" }
text = { path = "../text" } text = { path = "../text" }
util = { path = "../util" } util = { path = "../util" }
@ -34,8 +32,10 @@ log.workspace = true
libc = "0.2" libc = "0.2"
time.workspace = true time.workspace = true
gpui = { path = "../gpui", optional = true}
[dev-dependencies] [dev-dependencies]
gpui = { path = "../gpui", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] }
[features] [features]
test-support = [] test-support = ["gpui/test-support"]

View file

@ -93,33 +93,6 @@ pub struct Metadata {
pub is_dir: bool, pub is_dir: bool,
} }
impl From<lsp::CreateFileOptions> for CreateOptions {
fn from(options: lsp::CreateFileOptions) -> Self {
Self {
overwrite: options.overwrite.unwrap_or(false),
ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
}
}
}
impl From<lsp::RenameFileOptions> for RenameOptions {
fn from(options: lsp::RenameFileOptions) -> Self {
Self {
overwrite: options.overwrite.unwrap_or(false),
ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
}
}
}
impl From<lsp::DeleteFileOptions> for RemoveOptions {
fn from(options: lsp::DeleteFileOptions) -> Self {
Self {
recursive: options.recursive.unwrap_or(false),
ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
}
}
}
pub struct RealFs; pub struct RealFs;
#[async_trait::async_trait] #[async_trait::async_trait]

View file

@ -11,7 +11,7 @@ path = "src/gpui.rs"
doctest = false doctest = false
[features] [features]
test-support = ["backtrace", "dhat", "env_logger", "collections/test-support"] test-support = ["backtrace", "dhat", "env_logger", "collections/test-support", "util/test-support"]
[dependencies] [dependencies]
collections = { path = "../collections" } collections = { path = "../collections" }

View file

@ -4957,8 +4957,16 @@ impl Project {
if abs_path.ends_with("/") { if abs_path.ends_with("/") {
fs.create_dir(&abs_path).await?; fs.create_dir(&abs_path).await?;
} else { } else {
fs.create_file(&abs_path, op.options.map(Into::into).unwrap_or_default()) fs.create_file(
.await?; &abs_path,
op.options
.map(|options| fs::CreateOptions {
overwrite: options.overwrite.unwrap_or(false),
ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
})
.unwrap_or_default(),
)
.await?;
} }
} }
@ -4974,7 +4982,12 @@ impl Project {
fs.rename( fs.rename(
&source_abs_path, &source_abs_path,
&target_abs_path, &target_abs_path,
op.options.map(Into::into).unwrap_or_default(), op.options
.map(|options| fs::RenameOptions {
overwrite: options.overwrite.unwrap_or(false),
ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
})
.unwrap_or_default(),
) )
.await?; .await?;
} }
@ -4984,7 +4997,13 @@ impl Project {
.uri .uri
.to_file_path() .to_file_path()
.map_err(|_| anyhow!("can't convert URI to path"))?; .map_err(|_| anyhow!("can't convert URI to path"))?;
let options = op.options.map(Into::into).unwrap_or_default(); let options = op
.options
.map(|options| fs::RemoveOptions {
recursive: options.recursive.unwrap_or(false),
ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
})
.unwrap_or_default();
if abs_path.ends_with("/") { if abs_path.ends_with("/") {
fs.remove_dir(&abs_path, options).await?; fs.remove_dir(&abs_path, options).await?;
} else { } else {

View file

@ -12,6 +12,8 @@ path = "src/storybook.rs"
anyhow.workspace = true anyhow.workspace = true
clap = { version = "4.4", features = ["derive", "string"] } clap = { version = "4.4", features = ["derive", "string"] }
chrono = "0.4" chrono = "0.4"
fs = { path = "../fs" }
futures.workspace = true
gpui2 = { path = "../gpui2" } gpui2 = { path = "../gpui2" }
itertools = "0.11.0" itertools = "0.11.0"
log.workspace = true log.workspace = true

View file

@ -1,5 +1,8 @@
use std::path::PathBuf;
use std::str::FromStr;
use ui::prelude::*; use ui::prelude::*;
use ui::Breadcrumb; use ui::{Breadcrumb, HighlightedText, Symbol};
use crate::story::Story; use crate::story::Story;
@ -8,9 +11,35 @@ pub struct BreadcrumbStory {}
impl BreadcrumbStory { impl BreadcrumbStory {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, Breadcrumb>(cx)) .child(Story::title_for::<_, Breadcrumb>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child(Breadcrumb::new()) .child(Breadcrumb::new(
PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
vec![
Symbol(vec![
HighlightedText {
text: "impl ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "BreadcrumbStory".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
]),
Symbol(vec![
HighlightedText {
text: "fn ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "render".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
]),
],
))
} }
} }

View file

@ -12,8 +12,10 @@ pub struct BufferStory {}
impl BufferStory { impl BufferStory {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, Buffer<V>>(cx)) .child(Story::title_for::<_, Buffer>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child(div().w(rems(64.)).h_96().child(empty_buffer_example())) .child(div().w(rems(64.)).h_96().child(empty_buffer_example()))
.child(Story::label(cx, "Hello World (Rust)")) .child(Story::label(cx, "Hello World (Rust)"))
@ -21,14 +23,14 @@ impl BufferStory {
div() div()
.w(rems(64.)) .w(rems(64.))
.h_96() .h_96()
.child(hello_world_rust_buffer_example(cx)), .child(hello_world_rust_buffer_example(&theme)),
) )
.child(Story::label(cx, "Hello World (Rust) with Status")) .child(Story::label(cx, "Hello World (Rust) with Status"))
.child( .child(
div() div()
.w(rems(64.)) .w(rems(64.))
.h_96() .h_96()
.child(hello_world_rust_buffer_with_status_example(cx)), .child(hello_world_rust_buffer_with_status_example(&theme)),
) )
} }
} }

View file

@ -1,6 +1,6 @@
use chrono::DateTime; use chrono::DateTime;
use ui::prelude::*; use ui::prelude::*;
use ui::{ChatMessage, ChatPanel}; use ui::{ChatMessage, ChatPanel, Panel};
use crate::story::Story; use crate::story::Story;
@ -12,23 +12,35 @@ impl ChatPanelStory {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, ChatPanel<V>>(cx)) .child(Story::title_for::<_, ChatPanel<V>>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child(ChatPanel::new(ScrollState::default())) .child(Panel::new(
ScrollState::default(),
|_, _| vec![ChatPanel::new(ScrollState::default()).into_any()],
Box::new(()),
))
.child(Story::label(cx, "With Mesages")) .child(Story::label(cx, "With Mesages"))
.child(ChatPanel::new(ScrollState::default()).with_messages(vec![ .child(Panel::new(
ChatMessage::new( ScrollState::default(),
"osiewicz".to_string(), |_, _| {
"is this thing on?".to_string(), vec![ChatPanel::new(ScrollState::default())
DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z") .with_messages(vec![
.unwrap() ChatMessage::new(
.naive_local(), "osiewicz".to_string(),
), "is this thing on?".to_string(),
ChatMessage::new( DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
"maxdeviant".to_string(), .unwrap()
"Reading you loud and clear!".to_string(), .naive_local(),
DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z") ),
.unwrap() ChatMessage::new(
.naive_local(), "maxdeviant".to_string(),
), "Reading you loud and clear!".to_string(),
])) DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
.unwrap()
.naive_local(),
),
])
.into_any()]
},
Box::new(()),
))
} }
} }

View file

@ -11,7 +11,7 @@ impl FacepileStory {
let players = static_players(); let players = static_players();
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, ui::Facepile>(cx)) .child(Story::title_for::<_, Facepile>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child( .child(
div() div()

View file

@ -14,9 +14,10 @@ impl PanelStory {
.child(Panel::new( .child(Panel::new(
ScrollState::default(), ScrollState::default(),
|_, _| { |_, _| {
(0..100) vec![div()
.map(|ix| Label::new(format!("Item {}", ix + 1)).into_any()) .overflow_y_scroll(ScrollState::default())
.collect() .children((0..100).map(|ix| Label::new(format!("Item {}", ix + 1))))
.into_any()]
}, },
Box::new(()), Box::new(()),
)) ))

View file

@ -1,5 +1,5 @@
use ui::prelude::*; use ui::prelude::*;
use ui::ProjectPanel; use ui::{Panel, ProjectPanel};
use crate::story::Story; use crate::story::Story;
@ -11,6 +11,10 @@ impl ProjectPanelStory {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, ProjectPanel<V>>(cx)) .child(Story::title_for::<_, ProjectPanel<V>>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child(ProjectPanel::new(ScrollState::default())) .child(Panel::new(
ScrollState::default(),
|_, _| vec![ProjectPanel::new(ScrollState::default()).into_any()],
Box::new(()),
))
} }
} }

View file

@ -1,5 +1,5 @@
use ui::prelude::*; use ui::prelude::*;
use ui::TabBar; use ui::{Tab, TabBar};
use crate::story::Story; use crate::story::Story;
@ -11,6 +11,36 @@ impl TabBarStory {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, TabBar<V>>(cx)) .child(Story::title_for::<_, TabBar<V>>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child(TabBar::new(ScrollState::default())) .child(TabBar::new(vec![
Tab::new()
.title("Cargo.toml".to_string())
.current(false)
.git_status(GitStatus::Modified),
Tab::new()
.title("Channels Panel".to_string())
.current(false),
Tab::new()
.title("channels_panel.rs".to_string())
.current(true)
.git_status(GitStatus::Modified),
Tab::new()
.title("workspace.rs".to_string())
.current(false)
.git_status(GitStatus::Modified),
Tab::new()
.title("icon_button.rs".to_string())
.current(false),
Tab::new()
.title("storybook.rs".to_string())
.current(false)
.git_status(GitStatus::Created),
Tab::new().title("theme.rs".to_string()).current(false),
Tab::new()
.title("theme_registry.rs".to_string())
.current(false),
Tab::new()
.title("styleable_helpers.rs".to_string())
.current(false),
]))
} }
} }

View file

@ -1,5 +1,9 @@
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use ui::prelude::*; use ui::prelude::*;
use ui::Toolbar; use ui::{theme, Breadcrumb, HighlightColor, HighlightedText, Icon, IconButton, Symbol, Toolbar};
use crate::story::Story; use crate::story::Story;
@ -8,9 +12,59 @@ pub struct ToolbarStory {}
impl ToolbarStory { impl ToolbarStory {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
struct LeftItemsPayload {
pub theme: Arc<Theme>,
}
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, Toolbar>(cx)) .child(Story::title_for::<_, Toolbar<V>>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child(Toolbar::new()) .child(Toolbar::new(
|_, payload| {
let payload = payload.downcast_ref::<LeftItemsPayload>().unwrap();
let theme = payload.theme.clone();
vec![Breadcrumb::new(
PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
vec![
Symbol(vec![
HighlightedText {
text: "impl ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "ToolbarStory".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
]),
Symbol(vec![
HighlightedText {
text: "fn ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "render".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
]),
],
)
.into_any()]
},
Box::new(LeftItemsPayload {
theme: theme.clone(),
}),
|_, _| {
vec![
IconButton::new(Icon::InlayHint).into_any(),
IconButton::new(Icon::MagnifyingGlass).into_any(),
IconButton::new(Icon::MagicWand).into_any(),
]
},
Box::new(()),
))
} }
} }

View file

@ -9,7 +9,7 @@ pub struct AvatarStory {}
impl AvatarStory { impl AvatarStory {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, ui::Avatar>(cx)) .child(Story::title_for::<_, Avatar>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child(Avatar::new( .child(Avatar::new(
"https://avatars.githubusercontent.com/u/1714999?v=4", "https://avatars.githubusercontent.com/u/1714999?v=4",

View file

@ -12,7 +12,7 @@ impl IconStory {
let icons = Icon::iter(); let icons = Icon::iter();
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, ui::IconElement>(cx)) .child(Story::title_for::<_, IconElement>(cx))
.child(Story::label(cx, "All Icons")) .child(Story::label(cx, "All Icons"))
.child(div().flex().gap_3().children(icons.map(IconElement::new))) .child(div().flex().gap_3().children(icons.map(IconElement::new)))
} }

View file

@ -19,5 +19,8 @@ impl KitchenSinkStory {
.child(div().flex().flex_col().children_any(element_stories)) .child(div().flex().flex_col().children_any(element_stories))
.child(Story::label(cx, "Components")) .child(Story::label(cx, "Components"))
.child(div().flex().flex_col().children_any(component_stories)) .child(div().flex().flex_col().children_any(component_stories))
// Add a bit of space at the bottom of the kitchen sink so elements
// don't end up squished right up against the bottom of the screen.
.child(div().p_4())
} }
} }

View file

@ -4,7 +4,7 @@ mod stories;
mod story; mod story;
mod story_selector; mod story_selector;
use std::sync::Arc; use std::{process::Command, sync::Arc};
use ::theme as legacy_theme; use ::theme as legacy_theme;
use clap::Parser; use clap::Parser;
@ -38,11 +38,44 @@ struct Args {
theme: Option<String>, theme: Option<String>,
} }
async fn watch_zed_changes(fs: Arc<dyn fs::Fs>) -> Option<()> {
if std::env::var("ZED_HOT_RELOAD").is_err() {
return None;
}
use futures::StreamExt;
let mut events = fs
.watch(".".as_ref(), std::time::Duration::from_millis(100))
.await;
let mut current_child: Option<std::process::Child> = None;
while let Some(events) = events.next().await {
if !events.iter().any(|event| {
event
.path
.to_str()
.map(|path| path.contains("/crates/"))
.unwrap_or_default()
}) {
continue;
}
let child = current_child.take().map(|mut child| child.kill());
log::info!("Storybook changed, rebuilding...");
current_child = Some(
Command::new("cargo")
.args(["run", "-p", "storybook"])
.spawn()
.ok()?,
);
}
Some(())
}
fn main() { fn main() {
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
let args = Args::parse(); let args = Args::parse();
let fs = Arc::new(fs::RealFs);
gpui2::App::new(Assets).unwrap().run(move |cx| { gpui2::App::new(Assets).unwrap().run(move |cx| {
let mut store = SettingsStore::default(); let mut store = SettingsStore::default();
store store
@ -63,6 +96,10 @@ fn main() {
}) })
.and_then(|theme_name| theme_registry.get(&theme_name).ok()); .and_then(|theme_name| theme_registry.get(&theme_name).ok());
cx.spawn(|_| async move {
watch_zed_changes(fs).await;
})
.detach();
cx.add_window( cx.add_window(
gpui2::WindowOptions { gpui2::WindowOptions {
bounds: WindowBounds::Fixed(RectF::new(vec2f(0., 0.), vec2f(1700., 980.))), bounds: WindowBounds::Fixed(RectF::new(vec2f(0., 0.), vec2f(1700., 980.))),

View file

@ -13,3 +13,4 @@ settings = { path = "../settings" }
smallvec.workspace = true smallvec.workspace = true
strum = { version = "0.25.0", features = ["derive"] } strum = { version = "0.25.0", features = ["derive"] }
theme = { path = "../theme" } theme = { path = "../theme" }
rand = "0.8"

View file

@ -5,7 +5,7 @@ mod chat_panel;
mod collab_panel; mod collab_panel;
mod command_palette; mod command_palette;
mod context_menu; mod context_menu;
mod editor; mod editor_pane;
mod facepile; mod facepile;
mod icon_button; mod icon_button;
mod keybinding; mod keybinding;
@ -31,7 +31,7 @@ pub use chat_panel::*;
pub use collab_panel::*; pub use collab_panel::*;
pub use command_palette::*; pub use command_palette::*;
pub use context_menu::*; pub use context_menu::*;
pub use editor::*; pub use editor_pane::*;
pub use facepile::*; pub use facepile::*;
pub use icon_button::*; pub use icon_button::*;
pub use keybinding::*; pub use keybinding::*;

View file

@ -1,17 +1,35 @@
use crate::prelude::*; use std::path::PathBuf;
use gpui2::elements::div::Div;
use crate::{h_stack, theme}; use crate::{h_stack, theme};
use crate::{prelude::*, HighlightedText};
#[derive(Clone)]
pub struct Symbol(pub Vec<HighlightedText>);
#[derive(Element)] #[derive(Element)]
pub struct Breadcrumb {} pub struct Breadcrumb {
path: PathBuf,
symbols: Vec<Symbol>,
}
impl Breadcrumb { impl Breadcrumb {
pub fn new() -> Self { pub fn new(path: PathBuf, symbols: Vec<Symbol>) -> Self {
Self {} Self { path, symbols }
}
fn render_separator<V: 'static>(&self, theme: &Theme) -> Div<V> {
div()
.child(" ")
.text_color(HighlightColor::Default.hsla(theme))
} }
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx); let theme = theme(cx);
let symbols_len = self.symbols.len();
h_stack() h_stack()
.px_1() .px_1()
// TODO: Read font from theme (or settings?). // TODO: Read font from theme (or settings?).
@ -21,11 +39,33 @@ impl Breadcrumb {
.rounded_md() .rounded_md()
.hover() .hover()
.fill(theme.highest.base.hovered.background) .fill(theme.highest.base.hovered.background)
// TODO: Replace hardcoded breadcrumbs. .child(self.path.clone().to_str().unwrap().to_string())
.child("crates/ui/src/components/toolbar.rs") .child(if !self.symbols.is_empty() {
.child(" ") self.render_separator(&theme)
.child("impl Breadcrumb") } else {
.child(" ") div()
.child("fn render") })
.child(
div().flex().children(
self.symbols
.iter()
.enumerate()
// TODO: Could use something like `intersperse` here instead.
.flat_map(|(ix, symbol)| {
let mut items =
vec![div().flex().children(symbol.0.iter().map(|segment| {
div().child(segment.text.clone()).text_color(segment.color)
}))];
let is_last_segment = ix == symbols_len - 1;
if !is_last_segment {
items.push(self.render_separator(&theme));
}
items
})
.collect::<Vec<_>>(),
),
)
} }
} }

View file

@ -1,5 +1,3 @@
use std::marker::PhantomData;
use gpui2::{Hsla, WindowContext}; use gpui2::{Hsla, WindowContext};
use crate::prelude::*; use crate::prelude::*;
@ -33,6 +31,7 @@ pub struct BufferRow {
pub show_line_number: bool, pub show_line_number: bool,
} }
#[derive(Clone)]
pub struct BufferRows { pub struct BufferRows {
pub show_line_numbers: bool, pub show_line_numbers: bool,
pub rows: Vec<BufferRow>, pub rows: Vec<BufferRow>,
@ -108,9 +107,8 @@ impl BufferRow {
} }
} }
#[derive(Element)] #[derive(Element, Clone)]
pub struct Buffer<V: 'static> { pub struct Buffer {
view_type: PhantomData<V>,
scroll_state: ScrollState, scroll_state: ScrollState,
rows: Option<BufferRows>, rows: Option<BufferRows>,
readonly: bool, readonly: bool,
@ -119,10 +117,9 @@ pub struct Buffer<V: 'static> {
path: Option<String>, path: Option<String>,
} }
impl<V: 'static> Buffer<V> { impl Buffer {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
view_type: PhantomData,
scroll_state: ScrollState::default(), scroll_state: ScrollState::default(),
rows: Some(BufferRows::default()), rows: Some(BufferRows::default()),
readonly: false, readonly: false,
@ -161,7 +158,7 @@ impl<V: 'static> Buffer<V> {
self self
} }
fn render_row(row: BufferRow, cx: &WindowContext) -> impl IntoElement<V> { fn render_row<V: 'static>(row: BufferRow, cx: &WindowContext) -> impl IntoElement<V> {
let theme = theme(cx); let theme = theme(cx);
let system_color = SystemColor::new(); let system_color = SystemColor::new();
@ -172,28 +169,35 @@ impl<V: 'static> Buffer<V> {
}; };
let line_number_color = if row.current { let line_number_color = if row.current {
HighlightColor::Default.hsla(cx) HighlightColor::Default.hsla(&theme)
} else { } else {
HighlightColor::Comment.hsla(cx) HighlightColor::Comment.hsla(&theme)
}; };
h_stack() h_stack()
.fill(line_background) .fill(line_background)
.w_full()
.gap_2() .gap_2()
.px_2() .px_1()
.child(h_stack().w_4().h_full().px_1().when(row.code_action, |c| { .child(
div().child(IconElement::new(Icon::Bolt)) h_stack()
})) .w_4()
.h_full()
.px_0p5()
.when(row.code_action, |c| {
div().child(IconElement::new(Icon::Bolt))
}),
)
.when(row.show_line_number, |this| { .when(row.show_line_number, |this| {
this.child( this.child(
h_stack().justify_end().px_1().w_4().child( h_stack().justify_end().px_0p5().w_3().child(
div() div()
.text_color(line_number_color) .text_color(line_number_color)
.child(row.line_number.to_string()), .child(row.line_number.to_string()),
), ),
) )
}) })
.child(div().mx_1().w_1().h_full().fill(row.status.hsla(cx))) .child(div().mx_0p5().w_1().h_full().fill(row.status.hsla(cx)))
.children(row.line.map(|line| { .children(row.line.map(|line| {
div() div()
.flex() .flex()
@ -205,7 +209,7 @@ impl<V: 'static> Buffer<V> {
})) }))
} }
fn render_rows(&self, cx: &WindowContext) -> Vec<impl IntoElement<V>> { fn render_rows<V: 'static>(&self, cx: &WindowContext) -> Vec<impl IntoElement<V>> {
match &self.rows { match &self.rows {
Some(rows) => rows Some(rows) => rows
.rows .rows
@ -216,7 +220,7 @@ impl<V: 'static> Buffer<V> {
} }
} }
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx); let theme = theme(cx);
let rows = self.render_rows(cx); let rows = self.render_rows(cx);
v_stack() v_stack()

View file

@ -4,13 +4,12 @@ use chrono::NaiveDateTime;
use crate::prelude::*; use crate::prelude::*;
use crate::theme::theme; use crate::theme::theme;
use crate::{Icon, IconButton, Input, Label, LabelColor, Panel, PanelSide}; use crate::{Icon, IconButton, Input, Label, LabelColor};
#[derive(Element)] #[derive(Element)]
pub struct ChatPanel<V: 'static> { pub struct ChatPanel<V: 'static> {
view_type: PhantomData<V>, view_type: PhantomData<V>,
scroll_state: ScrollState, scroll_state: ScrollState,
current_side: PanelSide,
messages: Vec<ChatMessage>, messages: Vec<ChatMessage>,
} }
@ -19,16 +18,10 @@ impl<V: 'static> ChatPanel<V> {
Self { Self {
view_type: PhantomData, view_type: PhantomData,
scroll_state, scroll_state,
current_side: PanelSide::default(),
messages: Vec::new(), messages: Vec::new(),
} }
} }
pub fn side(mut self, side: PanelSide) -> Self {
self.current_side = side;
self
}
pub fn with_messages(mut self, messages: Vec<ChatMessage>) -> Self { pub fn with_messages(mut self, messages: Vec<ChatMessage>) -> Self {
self.messages = messages; self.messages = messages;
self self
@ -37,38 +30,33 @@ impl<V: 'static> ChatPanel<V> {
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx); let theme = theme(cx);
struct PanelPayload { div()
pub scroll_state: ScrollState, .flex()
pub messages: Vec<ChatMessage>, .flex_col()
} .justify_between()
.h_full()
Panel::new( .px_2()
self.scroll_state.clone(), .gap_2()
|_, payload| { // Header
let payload = payload.downcast_ref::<PanelPayload>().unwrap(); .child(
div()
vec![div()
.flex() .flex()
.flex_col() .justify_between()
.h_full() .py_2()
.px_2() .child(div().flex().child(Label::new("#design")))
.gap_2()
// Header
.child( .child(
div() div()
.flex() .flex()
.justify_between() .items_center()
.gap_2() .gap_px()
.child(div().flex().child(Label::new("#design"))) .child(IconButton::new(Icon::File))
.child( .child(IconButton::new(Icon::AudioOn)),
div() ),
.flex() )
.items_center() .child(
.gap_px() div()
.child(IconButton::new(Icon::File)) .flex()
.child(IconButton::new(Icon::AudioOn)), .flex_col()
),
)
// Chat Body // Chat Body
.child( .child(
div() div()
@ -76,19 +64,12 @@ impl<V: 'static> ChatPanel<V> {
.flex() .flex()
.flex_col() .flex_col()
.gap_3() .gap_3()
.overflow_y_scroll(payload.scroll_state.clone()) .overflow_y_scroll(self.scroll_state.clone())
.children(payload.messages.clone()), .children(self.messages.clone()),
) )
// Composer // Composer
.child(div().flex().gap_2().child(Input::new("Message #design"))) .child(div().flex().my_2().child(Input::new("Message #design"))),
.into_any()] )
},
Box::new(PanelPayload {
scroll_state: self.scroll_state.clone(),
messages: self.messages.clone(),
}),
)
.side(self.current_side)
} }
} }

View file

@ -1,25 +0,0 @@
use std::marker::PhantomData;
use crate::prelude::*;
use crate::{Buffer, Toolbar};
#[derive(Element)]
struct Editor<V: 'static> {
view_type: PhantomData<V>,
toolbar: Toolbar,
buffer: Buffer<V>,
}
impl<V: 'static> Editor<V> {
pub fn new(toolbar: Toolbar, buffer: Buffer<V>) -> Self {
Self {
view_type: PhantomData,
toolbar,
buffer,
}
}
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
div().child(self.toolbar.clone())
}
}

View file

@ -0,0 +1,60 @@
use std::marker::PhantomData;
use std::path::PathBuf;
use crate::prelude::*;
use crate::{v_stack, Breadcrumb, Buffer, Icon, IconButton, Symbol, Tab, TabBar, Toolbar};
pub struct Editor {
pub tabs: Vec<Tab>,
pub path: PathBuf,
pub symbols: Vec<Symbol>,
pub buffer: Buffer,
}
#[derive(Element)]
pub struct EditorPane<V: 'static> {
view_type: PhantomData<V>,
editor: Editor,
}
impl<V: 'static> EditorPane<V> {
pub fn new(editor: Editor) -> Self {
Self {
view_type: PhantomData,
editor,
}
}
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
struct LeftItemsPayload {
path: PathBuf,
symbols: Vec<Symbol>,
}
v_stack()
.w_full()
.h_full()
.flex_1()
.child(TabBar::new(self.editor.tabs.clone()))
.child(Toolbar::new(
|_, payload| {
let payload = payload.downcast_ref::<LeftItemsPayload>().unwrap();
vec![Breadcrumb::new(payload.path.clone(), payload.symbols.clone()).into_any()]
},
Box::new(LeftItemsPayload {
path: self.editor.path.clone(),
symbols: self.editor.symbols.clone(),
}),
|_, _| {
vec![
IconButton::new(Icon::InlayHint).into_any(),
IconButton::new(Icon::MagnifyingGlass).into_any(),
IconButton::new(Icon::MagicWand).into_any(),
]
},
Box::new(()),
))
.child(self.editor.buffer.clone())
}
}

View file

@ -105,16 +105,12 @@ impl<V: 'static> Panel<V> {
let theme = theme(cx); let theme = theme(cx);
let panel_base; let panel_base;
let current_width = if let Some(width) = self.width { let current_width = self.width.unwrap_or(self.initial_width);
width
} else {
self.initial_width
};
match self.current_side { match self.current_side {
PanelSide::Left => { PanelSide::Left => {
panel_base = v_stack() panel_base = v_stack()
.overflow_y_scroll(self.scroll_state.clone()) .flex_initial()
.h_full() .h_full()
.w(current_width) .w(current_width)
.fill(theme.middle.base.default.background) .fill(theme.middle.base.default.background)
@ -123,20 +119,20 @@ impl<V: 'static> Panel<V> {
} }
PanelSide::Right => { PanelSide::Right => {
panel_base = v_stack() panel_base = v_stack()
.overflow_y_scroll(self.scroll_state.clone()) .flex_initial()
.h_full() .h_full()
.w(current_width) .w(current_width)
.fill(theme.middle.base.default.background) .fill(theme.middle.base.default.background)
.border_r() .border_l()
.border_color(theme.middle.base.default.border); .border_color(theme.middle.base.default.border);
} }
PanelSide::Bottom => { PanelSide::Bottom => {
panel_base = v_stack() panel_base = v_stack()
.overflow_y_scroll(self.scroll_state.clone()) .flex_initial()
.w_full() .w_full()
.h(current_width) .h(current_width)
.fill(theme.middle.base.default.background) .fill(theme.middle.base.default.background)
.border_r() .border_t()
.border_color(theme.middle.base.default.border); .border_color(theme.middle.base.default.border);
} }
} }

View file

@ -38,9 +38,8 @@ impl PlayerStack {
div().flex().justify_center().w_full().child( div().flex().justify_center().w_full().child(
div() div()
.w_4() .w_4()
.h_1() .h_0p5()
.rounded_bl_sm() .rounded_sm()
.rounded_br_sm()
.fill(player.cursor_color(cx)), .fill(player.cursor_color(cx)),
), ),
) )
@ -50,7 +49,7 @@ impl PlayerStack {
.items_center() .items_center()
.justify_center() .justify_center()
.h_6() .h_6()
.px_1() .pl_1()
.rounded_lg() .rounded_lg()
.fill(if followers.is_none() { .fill(if followers.is_none() {
system_color.transparent system_color.transparent
@ -59,7 +58,7 @@ impl PlayerStack {
}) })
.child(Avatar::new(player.avatar_src().to_string())) .child(Avatar::new(player.avatar_src().to_string()))
.children(followers.map(|followers| { .children(followers.map(|followers| {
div().neg_mr_1().child(Facepile::new(followers.into_iter())) div().neg_ml_2().child(Facepile::new(followers.into_iter()))
})), })),
) )
} }

View file

@ -1,17 +1,15 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::Arc;
use crate::prelude::*; use crate::prelude::*;
use crate::{ use crate::{
static_project_panel_project_items, static_project_panel_single_items, theme, Input, List, static_project_panel_project_items, static_project_panel_single_items, theme, Input, List,
ListHeader, Panel, PanelSide, Theme, ListHeader,
}; };
#[derive(Element)] #[derive(Element)]
pub struct ProjectPanel<V: 'static> { pub struct ProjectPanel<V: 'static> {
view_type: PhantomData<V>, view_type: PhantomData<V>,
scroll_state: ScrollState, scroll_state: ScrollState,
current_side: PanelSide,
} }
impl<V: 'static> ProjectPanel<V> { impl<V: 'static> ProjectPanel<V> {
@ -19,69 +17,42 @@ impl<V: 'static> ProjectPanel<V> {
Self { Self {
view_type: PhantomData, view_type: PhantomData,
scroll_state, scroll_state,
current_side: PanelSide::default(),
} }
} }
pub fn side(mut self, side: PanelSide) -> Self {
self.current_side = side;
self
}
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
struct PanelPayload { let theme = theme(cx);
pub theme: Arc<Theme>,
pub scroll_state: ScrollState,
}
Panel::new( div()
self.scroll_state.clone(), .flex()
|_, payload| { .flex_col()
let payload = payload.downcast_ref::<PanelPayload>().unwrap(); .w_full()
.h_full()
let theme = payload.theme.clone(); .px_2()
.fill(theme.middle.base.default.background)
vec![div() .child(
div()
.w_56()
.flex() .flex()
.flex_col() .flex_col()
.w_56() .overflow_y_scroll(ScrollState::default())
.h_full()
.px_2()
.fill(theme.middle.base.default.background)
.child( .child(
div() List::new(static_project_panel_single_items())
.w_56() .header(ListHeader::new("FILES").set_toggle(ToggleState::Toggled))
.flex() .empty_message("No files in directory")
.flex_col() .set_toggle(ToggleState::Toggled),
.overflow_y_scroll(payload.scroll_state.clone())
.child(
List::new(static_project_panel_single_items())
.header(
ListHeader::new("FILES").set_toggle(ToggleState::Toggled),
)
.empty_message("No files in directory")
.set_toggle(ToggleState::Toggled),
)
.child(
List::new(static_project_panel_project_items())
.header(
ListHeader::new("PROJECT").set_toggle(ToggleState::Toggled),
)
.empty_message("No folders in directory")
.set_toggle(ToggleState::Toggled),
),
) )
.child( .child(
Input::new("Find something...") List::new(static_project_panel_project_items())
.value("buffe".to_string()) .header(ListHeader::new("PROJECT").set_toggle(ToggleState::Toggled))
.state(InteractionState::Focused), .empty_message("No folders in directory")
) .set_toggle(ToggleState::Toggled),
.into_any()] ),
}, )
Box::new(PanelPayload { .child(
theme: theme(cx), Input::new("Find something...")
scroll_state: self.scroll_state.clone(), .value("buffe".to_string())
}), .state(InteractionState::Focused),
) )
} }
} }

View file

@ -1,7 +1,7 @@
use crate::prelude::*; use crate::prelude::*;
use crate::{theme, Icon, IconColor, IconElement, Label, LabelColor}; use crate::{theme, Icon, IconColor, IconElement, Label, LabelColor};
#[derive(Element)] #[derive(Element, Clone)]
pub struct Tab { pub struct Tab {
title: String, title: String,
icon: Option<Icon>, icon: Option<Icon>,

View file

@ -7,20 +7,27 @@ use crate::{theme, Icon, IconButton, Tab};
pub struct TabBar<V: 'static> { pub struct TabBar<V: 'static> {
view_type: PhantomData<V>, view_type: PhantomData<V>,
scroll_state: ScrollState, scroll_state: ScrollState,
tabs: Vec<Tab>,
} }
impl<V: 'static> TabBar<V> { impl<V: 'static> TabBar<V> {
pub fn new(scroll_state: ScrollState) -> Self { pub fn new(tabs: Vec<Tab>) -> Self {
Self { Self {
view_type: PhantomData, view_type: PhantomData,
scroll_state, scroll_state: ScrollState::default(),
tabs,
} }
} }
pub fn bind_scroll_state(&mut self, scroll_state: ScrollState) {
self.scroll_state = scroll_state;
}
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx); let theme = theme(cx);
let can_navigate_back = true; let can_navigate_back = true;
let can_navigate_forward = false; let can_navigate_forward = false;
div() div()
.w_full() .w_full()
.flex() .flex()
@ -54,51 +61,7 @@ impl<V: 'static> TabBar<V> {
div() div()
.flex() .flex()
.overflow_x_scroll(self.scroll_state.clone()) .overflow_x_scroll(self.scroll_state.clone())
.child( .children(self.tabs.clone()),
Tab::new()
.title("Cargo.toml".to_string())
.current(false)
.git_status(GitStatus::Modified),
)
.child(
Tab::new()
.title("Channels Panel".to_string())
.current(false),
)
.child(
Tab::new()
.title("channels_panel.rs".to_string())
.current(true)
.git_status(GitStatus::Modified),
)
.child(
Tab::new()
.title("workspace.rs".to_string())
.current(false)
.git_status(GitStatus::Modified),
)
.child(
Tab::new()
.title("icon_button.rs".to_string())
.current(false),
)
.child(
Tab::new()
.title("storybook.rs".to_string())
.current(false)
.git_status(GitStatus::Created),
)
.child(Tab::new().title("theme.rs".to_string()).current(false))
.child(
Tab::new()
.title("theme_registry.rs".to_string())
.current(false),
)
.child(
Tab::new()
.title("styleable_helpers.rs".to_string())
.current(false),
),
), ),
) )
// Right Side // Right Side

View file

@ -1,3 +1,5 @@
use std::sync::Arc;
use gpui2::geometry::{relative, rems, Size}; use gpui2::geometry::{relative, rems, Size};
use crate::prelude::*; use crate::prelude::*;
@ -20,6 +22,7 @@ impl Terminal {
div() div()
.flex() .flex()
.flex_col() .flex_col()
.w_full()
.child( .child(
// Terminal Tabs. // Terminal Tabs.
div() div()
@ -70,8 +73,12 @@ impl Terminal {
width: relative(1.).into(), width: relative(1.).into(),
height: rems(36.).into(), height: rems(36.).into(),
}, },
|_, _| vec![], |_, payload| {
Box::new(()), let theme = payload.downcast_ref::<Arc<Theme>>().unwrap();
vec![crate::static_data::terminal_buffer(&theme).into_any()]
},
Box::new(theme),
)) ))
} }
} }

View file

@ -2,16 +2,24 @@ use std::marker::PhantomData;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::sync::Arc; use std::sync::Arc;
use crate::prelude::*; use crate::{prelude::*, PlayerWithCallStatus};
use crate::{ use crate::{
static_players_with_call_status, theme, Avatar, Button, Icon, IconButton, IconColor, theme, Avatar, Button, Icon, IconButton, IconColor, PlayerStack, ToolDivider, TrafficLights,
PlayerStack, ToolDivider, TrafficLights,
}; };
#[derive(Clone)]
pub struct Livestream {
pub players: Vec<PlayerWithCallStatus>,
pub channel: Option<String>, // projects
// windows
}
#[derive(Element)] #[derive(Element)]
pub struct TitleBar<V: 'static> { pub struct TitleBar<V: 'static> {
view_type: PhantomData<V>, view_type: PhantomData<V>,
/// If the window is active from the OS's perspective.
is_active: Arc<AtomicBool>, is_active: Arc<AtomicBool>,
livestream: Option<Livestream>,
} }
impl<V: 'static> TitleBar<V> { impl<V: 'static> TitleBar<V> {
@ -28,14 +36,24 @@ impl<V: 'static> TitleBar<V> {
Self { Self {
view_type: PhantomData, view_type: PhantomData,
is_active, is_active,
livestream: None,
} }
} }
pub fn set_livestream(mut self, livestream: Option<Livestream>) -> Self {
self.livestream = livestream;
self
}
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx); let theme = theme(cx);
let has_focus = cx.window_is_active(); let has_focus = cx.window_is_active();
let player_list = static_players_with_call_status().into_iter(); let player_list = if let Some(livestream) = &self.livestream {
livestream.players.clone().into_iter()
} else {
vec![].into_iter()
};
div() div()
.flex() .flex()
@ -61,7 +79,8 @@ impl<V: 'static> TitleBar<V> {
.child(Button::new("zed")) .child(Button::new("zed"))
.child(Button::new("nate/gpui2-ui-components")), .child(Button::new("nate/gpui2-ui-components")),
) )
.children(player_list.map(|p| PlayerStack::new(p))), .children(player_list.map(|p| PlayerStack::new(p)))
.child(IconButton::new(Icon::Plus)),
) )
.child( .child(
div() div()

View file

@ -1,33 +1,49 @@
use crate::prelude::*; use crate::prelude::*;
use crate::{theme, Breadcrumb, Icon, IconButton}; use crate::theme;
#[derive(Clone)] #[derive(Clone)]
pub struct ToolbarItem {} pub struct ToolbarItem {}
#[derive(Element, Clone)] #[derive(Element)]
pub struct Toolbar { pub struct Toolbar<V: 'static> {
items: Vec<ToolbarItem>, left_items: HackyChildren<V>,
left_items_payload: HackyChildrenPayload,
right_items: HackyChildren<V>,
right_items_payload: HackyChildrenPayload,
} }
impl Toolbar { impl<V: 'static> Toolbar<V> {
pub fn new() -> Self { pub fn new(
Self { items: Vec::new() } left_items: HackyChildren<V>,
left_items_payload: HackyChildrenPayload,
right_items: HackyChildren<V>,
right_items_payload: HackyChildrenPayload,
) -> Self {
Self {
left_items,
left_items_payload,
right_items,
right_items_payload,
}
} }
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx); let theme = theme(cx);
div() div()
.fill(theme.highest.base.default.background)
.p_2() .p_2()
.flex() .flex()
.justify_between() .justify_between()
.child(Breadcrumb::new())
.child( .child(
div() div()
.flex() .flex()
.child(IconButton::new(Icon::InlayHint)) .children_any((self.left_items)(cx, self.left_items_payload.as_ref())),
.child(IconButton::new(Icon::MagnifyingGlass)) )
.child(IconButton::new(Icon::MagicWand)), .child(
div()
.flex()
.children_any((self.right_items)(cx, self.right_items_payload.as_ref())),
) )
} }
} }

View file

@ -1,10 +1,15 @@
use std::sync::Arc;
use chrono::DateTime; use chrono::DateTime;
use gpui2::geometry::{relative, rems, Size}; use gpui2::geometry::{relative, rems, Size};
use crate::prelude::*;
use crate::{ use crate::{
theme, v_stack, ChatMessage, ChatPanel, Pane, PaneGroup, Panel, PanelAllowedSides, PanelSide, hello_world_rust_editor_with_status_example, prelude::*, random_players_with_call_status,
ProjectPanel, SplitDirection, StatusBar, Terminal, TitleBar, Livestream,
};
use crate::{
theme, v_stack, ChatMessage, ChatPanel, EditorPane, Pane, PaneGroup, Panel, PanelAllowedSides,
PanelSide, ProjectPanel, SplitDirection, StatusBar, Terminal, TitleBar,
}; };
#[derive(Element, Default)] #[derive(Element, Default)]
@ -17,6 +22,8 @@ pub struct WorkspaceElement {
impl WorkspaceElement { impl WorkspaceElement {
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> { fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx).clone();
let temp_size = rems(36.).into(); let temp_size = rems(36.).into();
let root_group = PaneGroup::new_groups( let root_group = PaneGroup::new_groups(
@ -29,8 +36,15 @@ impl WorkspaceElement {
width: relative(1.).into(), width: relative(1.).into(),
height: temp_size, height: temp_size,
}, },
|_, _| vec![Terminal::new().into_any()], |_, payload| {
Box::new(()), let theme = payload.downcast_ref::<Arc<Theme>>().unwrap();
vec![EditorPane::new(hello_world_rust_editor_with_status_example(
&theme,
))
.into_any()]
},
Box::new(theme.clone()),
), ),
Pane::new( Pane::new(
ScrollState::default(), ScrollState::default(),
@ -51,8 +65,15 @@ impl WorkspaceElement {
width: relative(1.).into(), width: relative(1.).into(),
height: relative(1.).into(), height: relative(1.).into(),
}, },
|_, _| vec![Terminal::new().into_any()], |_, payload| {
Box::new(()), let theme = payload.downcast_ref::<Arc<Theme>>().unwrap();
vec![EditorPane::new(hello_world_rust_editor_with_status_example(
&theme,
))
.into_any()]
},
Box::new(theme.clone()),
)], )],
SplitDirection::Vertical, SplitDirection::Vertical,
), ),
@ -60,8 +81,6 @@ impl WorkspaceElement {
SplitDirection::Horizontal, SplitDirection::Horizontal,
); );
let theme = theme(cx).clone();
div() div()
.size_full() .size_full()
.flex() .flex()
@ -72,7 +91,10 @@ impl WorkspaceElement {
.items_start() .items_start()
.text_color(theme.lowest.base.default.foreground) .text_color(theme.lowest.base.default.foreground)
.fill(theme.lowest.base.default.background) .fill(theme.lowest.base.default.background)
.child(TitleBar::new(cx)) .child(TitleBar::new(cx).set_livestream(Some(Livestream {
players: random_players_with_call_status(7),
channel: Some("gpui2-ui".to_string()),
})))
.child( .child(
div() div()
.flex_1() .flex_1()
@ -84,8 +106,12 @@ impl WorkspaceElement {
.border_b() .border_b()
.border_color(theme.lowest.base.default.border) .border_color(theme.lowest.base.default.border)
.child( .child(
ProjectPanel::new(self.left_panel_scroll_state.clone()) Panel::new(
.side(PanelSide::Left), self.left_panel_scroll_state.clone(),
|_, payload| vec![ProjectPanel::new(ScrollState::default()).into_any()],
Box::new(()),
)
.side(PanelSide::Left),
) )
.child( .child(
v_stack() v_stack()
@ -110,26 +136,37 @@ impl WorkspaceElement {
.side(PanelSide::Bottom), .side(PanelSide::Bottom),
), ),
) )
.child(ChatPanel::new(ScrollState::default()).with_messages(vec![ .child(
ChatMessage::new( Panel::new(
"osiewicz".to_string(), self.right_panel_scroll_state.clone(),
"is this thing on?".to_string(), |_, payload| {
DateTime::parse_from_rfc3339( vec![ChatPanel::new(ScrollState::default())
"2023-09-27T15:40:52.707Z", .with_messages(vec![
) ChatMessage::new(
.unwrap() "osiewicz".to_string(),
.naive_local(), "is this thing on?".to_string(),
), DateTime::parse_from_rfc3339(
ChatMessage::new( "2023-09-27T15:40:52.707Z",
"maxdeviant".to_string(), )
"Reading you loud and clear!".to_string(), .unwrap()
DateTime::parse_from_rfc3339( .naive_local(),
"2023-09-28T15:40:52.707Z", ),
) ChatMessage::new(
.unwrap() "maxdeviant".to_string(),
.naive_local(), "Reading you loud and clear!".to_string(),
), DateTime::parse_from_rfc3339(
])), "2023-09-28T15:40:52.707Z",
)
.unwrap()
.naive_local(),
),
])
.into_any()]
},
Box::new(()),
)
.side(PanelSide::Right),
),
) )
.child(StatusBar::new()) .child(StatusBar::new())
} }

View file

@ -84,6 +84,7 @@ pub enum Icon {
Plus, Plus,
Quote, Quote,
Screen, Screen,
SelectAll,
Split, Split,
SplitMessage, SplitMessage,
Terminal, Terminal,
@ -131,6 +132,7 @@ impl Icon {
Icon::Plus => "icons/plus.svg", Icon::Plus => "icons/plus.svg",
Icon::Quote => "icons/quote.svg", Icon::Quote => "icons/quote.svg",
Icon::Screen => "icons/desktop.svg", Icon::Screen => "icons/desktop.svg",
Icon::SelectAll => "icons/select-all.svg",
Icon::Split => "icons/split.svg", Icon::Split => "icons/split.svg",
Icon::SplitMessage => "icons/split_message.svg", Icon::SplitMessage => "icons/split_message.svg",
Icon::Terminal => "icons/terminal.svg", Icon::Terminal => "icons/terminal.svg",

View file

@ -81,6 +81,7 @@ impl Input {
div() div()
.h_7() .h_7()
.w_full()
.px_2() .px_2()
.border() .border()
.border_color(border_color_default) .border_color(border_color_default)

View file

@ -65,7 +65,7 @@ impl PlayerCallStatus {
} }
} }
#[derive(Clone)] #[derive(PartialEq, Clone)]
pub struct Player { pub struct Player {
index: usize, index: usize,
avatar_src: String, avatar_src: String,
@ -73,6 +73,7 @@ pub struct Player {
status: PlayerStatus, status: PlayerStatus,
} }
#[derive(Clone)]
pub struct PlayerWithCallStatus { pub struct PlayerWithCallStatus {
player: Player, player: Player,
call_status: PlayerCallStatus, call_status: PlayerCallStatus,

View file

@ -2,7 +2,7 @@ pub use gpui2::elements::div::{div, ScrollState};
pub use gpui2::style::{StyleHelpers, Styleable}; pub use gpui2::style::{StyleHelpers, Styleable};
pub use gpui2::{Element, IntoElement, ParentElement, ViewContext}; pub use gpui2::{Element, IntoElement, ParentElement, ViewContext};
pub use crate::{theme, ButtonVariant, HackyChildren, HackyChildrenPayload, InputVariant}; pub use crate::{theme, ButtonVariant, HackyChildren, HackyChildrenPayload, InputVariant, Theme};
use gpui2::{hsla, rgb, Hsla, WindowContext}; use gpui2::{hsla, rgb, Hsla, WindowContext};
use strum::EnumIter; use strum::EnumIter;
@ -40,8 +40,7 @@ pub enum HighlightColor {
} }
impl HighlightColor { impl HighlightColor {
pub fn hsla(&self, cx: &WindowContext) -> Hsla { pub fn hsla(&self, theme: &Theme) -> Hsla {
let theme = theme(cx);
let system_color = SystemColor::new(); let system_color = SystemColor::new();
match self { match self {
@ -74,7 +73,7 @@ impl HighlightColor {
} }
} }
#[derive(Default, PartialEq, EnumIter)] #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
pub enum FileSystemStatus { pub enum FileSystemStatus {
#[default] #[default]
None, None,
@ -92,7 +91,7 @@ impl FileSystemStatus {
} }
} }
#[derive(Default, PartialEq, EnumIter, Clone, Copy)] #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
pub enum GitStatus { pub enum GitStatus {
#[default] #[default]
None, None,
@ -130,7 +129,7 @@ impl GitStatus {
} }
} }
#[derive(Default, PartialEq)] #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
pub enum DiagnosticStatus { pub enum DiagnosticStatus {
#[default] #[default]
None, None,
@ -139,14 +138,14 @@ pub enum DiagnosticStatus {
Info, Info,
} }
#[derive(Default, PartialEq)] #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
pub enum IconSide { pub enum IconSide {
#[default] #[default]
Left, Left,
Right, Right,
} }
#[derive(Default, PartialEq)] #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
pub enum OrderMethod { pub enum OrderMethod {
#[default] #[default]
Ascending, Ascending,
@ -154,14 +153,14 @@ pub enum OrderMethod {
MostRecent, MostRecent,
} }
#[derive(Default, PartialEq, Clone, Copy)] #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
pub enum Shape { pub enum Shape {
#[default] #[default]
Circle, Circle,
RoundedRectangle, RoundedRectangle,
} }
#[derive(Default, PartialEq, Clone, Copy)] #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)]
pub enum DisclosureControlVisibility { pub enum DisclosureControlVisibility {
#[default] #[default]
OnHover, OnHover,

View file

@ -1,12 +1,109 @@
use gpui2::WindowContext; use std::path::PathBuf;
use std::str::FromStr;
use rand::Rng;
use crate::{ use crate::{
Buffer, BufferRow, BufferRows, GitStatus, HighlightColor, HighlightedLine, HighlightedText, Buffer, BufferRow, BufferRows, Editor, FileSystemStatus, GitStatus, HighlightColor,
Icon, Keybinding, Label, LabelColor, ListEntry, ListEntrySize, ListItem, MicStatus, HighlightedLine, HighlightedText, Icon, Keybinding, Label, LabelColor, ListEntry,
ModifierKeys, PaletteItem, Player, PlayerCallStatus, PlayerWithCallStatus, ScreenShareStatus, ListEntrySize, ListItem, Livestream, MicStatus, ModifierKeys, PaletteItem, Player,
ToggleState, PlayerCallStatus, PlayerWithCallStatus, ScreenShareStatus, Symbol, Tab, Theme, ToggleState,
VideoStatus,
}; };
pub fn static_tabs_example() -> Vec<Tab> {
vec![
Tab::new()
.title("wip.rs".to_string())
.icon(Icon::FileRust)
.current(false)
.fs_status(FileSystemStatus::Deleted),
Tab::new()
.title("Cargo.toml".to_string())
.icon(Icon::FileToml)
.current(false)
.git_status(GitStatus::Modified),
Tab::new()
.title("Channels Panel".to_string())
.icon(Icon::Hash)
.current(false),
Tab::new()
.title("channels_panel.rs".to_string())
.icon(Icon::FileRust)
.current(true)
.git_status(GitStatus::Modified),
Tab::new()
.title("workspace.rs".to_string())
.current(false)
.icon(Icon::FileRust)
.git_status(GitStatus::Modified),
Tab::new()
.title("icon_button.rs".to_string())
.icon(Icon::FileRust)
.current(false),
Tab::new()
.title("storybook.rs".to_string())
.icon(Icon::FileRust)
.current(false)
.git_status(GitStatus::Created),
Tab::new()
.title("theme.rs".to_string())
.icon(Icon::FileRust)
.current(false),
Tab::new()
.title("theme_registry.rs".to_string())
.icon(Icon::FileRust)
.current(false),
Tab::new()
.title("styleable_helpers.rs".to_string())
.icon(Icon::FileRust)
.current(false),
]
}
pub fn static_tabs_1() -> Vec<Tab> {
vec![
Tab::new()
.title("project_panel.rs".to_string())
.icon(Icon::FileRust)
.current(false)
.fs_status(FileSystemStatus::Deleted),
Tab::new()
.title("tab_bar.rs".to_string())
.icon(Icon::FileRust)
.current(false)
.git_status(GitStatus::Modified),
Tab::new()
.title("workspace.rs".to_string())
.icon(Icon::FileRust)
.current(false),
Tab::new()
.title("tab.rs".to_string())
.icon(Icon::FileRust)
.current(true)
.git_status(GitStatus::Modified),
]
}
pub fn static_tabs_2() -> Vec<Tab> {
vec![
Tab::new()
.title("tab_bar.rs".to_string())
.icon(Icon::FileRust)
.current(false)
.fs_status(FileSystemStatus::Deleted),
Tab::new()
.title("static_data.rs".to_string())
.icon(Icon::FileRust)
.current(true)
.git_status(GitStatus::Modified),
]
}
pub fn static_tabs_3() -> Vec<Tab> {
vec![Tab::new().git_status(GitStatus::Created).current(true)]
}
pub fn static_players() -> Vec<Player> { pub fn static_players() -> Vec<Player> {
vec![ vec![
Player::new( Player::new(
@ -37,6 +134,154 @@ pub fn static_players() -> Vec<Player> {
] ]
} }
#[derive(Debug)]
pub struct PlayerData {
pub url: String,
pub name: String,
}
pub fn static_player_data() -> Vec<PlayerData> {
vec![
PlayerData {
url: "https://avatars.githubusercontent.com/u/1714999?v=4".into(),
name: "iamnbutler".into(),
},
PlayerData {
url: "https://avatars.githubusercontent.com/u/326587?v=4".into(),
name: "maxbrunsfeld".into(),
},
PlayerData {
url: "https://avatars.githubusercontent.com/u/482957?v=4".into(),
name: "as-cii".into(),
},
PlayerData {
url: "https://avatars.githubusercontent.com/u/1789?v=4".into(),
name: "nathansobo".into(),
},
PlayerData {
url: "https://avatars.githubusercontent.com/u/1486634?v=4".into(),
name: "ForLoveOfCats".into(),
},
PlayerData {
url: "https://avatars.githubusercontent.com/u/2690773?v=4".into(),
name: "SomeoneToIgnore".into(),
},
PlayerData {
url: "https://avatars.githubusercontent.com/u/19867440?v=4".into(),
name: "JosephTLyons".into(),
},
PlayerData {
url: "https://avatars.githubusercontent.com/u/24362066?v=4".into(),
name: "osiewicz".into(),
},
PlayerData {
url: "https://avatars.githubusercontent.com/u/22121886?v=4".into(),
name: "KCaverly".into(),
},
PlayerData {
url: "https://avatars.githubusercontent.com/u/1486634?v=4".into(),
name: "maxdeviant".into(),
},
]
}
pub fn create_static_players(player_data: Vec<PlayerData>) -> Vec<Player> {
let mut players = Vec::new();
for data in player_data {
players.push(Player::new(players.len(), data.url, data.name));
}
players
}
pub fn static_player_1(data: &Vec<PlayerData>) -> Player {
Player::new(1, data[0].url.clone(), data[0].name.clone())
}
pub fn static_player_2(data: &Vec<PlayerData>) -> Player {
Player::new(2, data[1].url.clone(), data[1].name.clone())
}
pub fn static_player_3(data: &Vec<PlayerData>) -> Player {
Player::new(3, data[2].url.clone(), data[2].name.clone())
}
pub fn static_player_4(data: &Vec<PlayerData>) -> Player {
Player::new(4, data[3].url.clone(), data[3].name.clone())
}
pub fn static_player_5(data: &Vec<PlayerData>) -> Player {
Player::new(5, data[4].url.clone(), data[4].name.clone())
}
pub fn static_player_6(data: &Vec<PlayerData>) -> Player {
Player::new(6, data[5].url.clone(), data[5].name.clone())
}
pub fn static_player_7(data: &Vec<PlayerData>) -> Player {
Player::new(7, data[6].url.clone(), data[6].name.clone())
}
pub fn static_player_8(data: &Vec<PlayerData>) -> Player {
Player::new(8, data[7].url.clone(), data[7].name.clone())
}
pub fn static_player_9(data: &Vec<PlayerData>) -> Player {
Player::new(9, data[8].url.clone(), data[8].name.clone())
}
pub fn static_player_10(data: &Vec<PlayerData>) -> Player {
Player::new(10, data[9].url.clone(), data[9].name.clone())
}
pub fn static_livestream() -> Livestream {
Livestream {
players: random_players_with_call_status(7),
channel: Some("gpui2-ui".to_string()),
}
}
pub fn populate_player_call_status(
player: Player,
followers: Option<Vec<Player>>,
) -> PlayerCallStatus {
let mut rng = rand::thread_rng();
let in_current_project: bool = rng.gen();
let disconnected: bool = rng.gen();
let voice_activity: f32 = rng.gen();
let mic_status = if rng.gen_bool(0.5) {
MicStatus::Muted
} else {
MicStatus::Unmuted
};
let video_status = if rng.gen_bool(0.5) {
VideoStatus::On
} else {
VideoStatus::Off
};
let screen_share_status = if rng.gen_bool(0.5) {
ScreenShareStatus::Shared
} else {
ScreenShareStatus::NotShared
};
PlayerCallStatus {
mic_status,
voice_activity,
video_status,
screen_share_status,
in_current_project,
disconnected,
following: None,
followers,
}
}
pub fn random_players_with_call_status(number_of_players: usize) -> Vec<PlayerWithCallStatus> {
let players = create_static_players(static_player_data());
let mut player_status = vec![];
for i in 0..number_of_players {
let followers = if i == 0 {
Some(vec![
players[1].clone(),
players[3].clone(),
players[5].clone(),
players[6].clone(),
])
} else if i == 1 {
Some(vec![players[2].clone(), players[6].clone()])
} else {
None
};
let call_status = populate_player_call_status(players[i].clone(), followers);
player_status.push(PlayerWithCallStatus::new(players[i].clone(), call_status));
}
player_status
}
pub fn static_players_with_call_status() -> Vec<PlayerWithCallStatus> { pub fn static_players_with_call_status() -> Vec<PlayerWithCallStatus> {
let players = static_players(); let players = static_players();
let mut player_0_status = PlayerCallStatus::new(); let mut player_0_status = PlayerCallStatus::new();
@ -123,7 +368,7 @@ pub fn static_project_panel_project_items() -> Vec<ListItem> {
.left_icon(Icon::FolderOpen.into()) .left_icon(Icon::FolderOpen.into())
.indent_level(3) .indent_level(3)
.set_toggle(ToggleState::Toggled), .set_toggle(ToggleState::Toggled),
ListEntry::new(Label::new("derrive_element.rs")) ListEntry::new(Label::new("derive_element.rs"))
.left_icon(Icon::FileRust.into()) .left_icon(Icon::FileRust.into())
.indent_level(4), .indent_level(4),
ListEntry::new(Label::new("storybook").color(LabelColor::Modified)) ListEntry::new(Label::new("storybook").color(LabelColor::Modified))
@ -337,33 +582,49 @@ pub fn example_editor_actions() -> Vec<PaletteItem> {
] ]
} }
pub fn empty_buffer_example<V: 'static>() -> Buffer<V> { pub fn empty_editor_example() -> Editor {
Editor {
tabs: static_tabs_example(),
path: PathBuf::from_str("crates/ui/src/static_data.rs").unwrap(),
symbols: vec![],
buffer: empty_buffer_example(),
}
}
pub fn empty_buffer_example() -> Buffer {
Buffer::new().set_rows(Some(BufferRows::default())) Buffer::new().set_rows(Some(BufferRows::default()))
} }
pub fn hello_world_rust_buffer_example<V: 'static>(cx: &WindowContext) -> Buffer<V> { pub fn hello_world_rust_editor_example(theme: &Theme) -> Editor {
Editor {
tabs: static_tabs_example(),
path: PathBuf::from_str("crates/ui/src/static_data.rs").unwrap(),
symbols: vec![Symbol(vec![
HighlightedText {
text: "fn ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "main".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
])],
buffer: hello_world_rust_buffer_example(theme),
}
}
pub fn hello_world_rust_buffer_example(theme: &Theme) -> Buffer {
Buffer::new() Buffer::new()
.set_title("hello_world.rs".to_string()) .set_title("hello_world.rs".to_string())
.set_path("src/hello_world.rs".to_string()) .set_path("src/hello_world.rs".to_string())
.set_language("rust".to_string()) .set_language("rust".to_string())
.set_rows(Some(BufferRows { .set_rows(Some(BufferRows {
show_line_numbers: true, show_line_numbers: true,
rows: hello_world_rust_buffer_rows(cx), rows: hello_world_rust_buffer_rows(theme),
})) }))
} }
pub fn hello_world_rust_buffer_with_status_example<V: 'static>(cx: &WindowContext) -> Buffer<V> { pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec<BufferRow> {
Buffer::new()
.set_title("hello_world.rs".to_string())
.set_path("src/hello_world.rs".to_string())
.set_language("rust".to_string())
.set_rows(Some(BufferRows {
show_line_numbers: true,
rows: hello_world_rust_with_status_buffer_rows(cx),
}))
}
pub fn hello_world_rust_buffer_rows(cx: &WindowContext) -> Vec<BufferRow> {
let show_line_number = true; let show_line_number = true;
vec![ vec![
@ -375,15 +636,15 @@ pub fn hello_world_rust_buffer_rows(cx: &WindowContext) -> Vec<BufferRow> {
highlighted_texts: vec![ highlighted_texts: vec![
HighlightedText { HighlightedText {
text: "fn ".to_string(), text: "fn ".to_string(),
color: HighlightColor::Keyword.hsla(cx), color: HighlightColor::Keyword.hsla(&theme),
}, },
HighlightedText { HighlightedText {
text: "main".to_string(), text: "main".to_string(),
color: HighlightColor::Function.hsla(cx), color: HighlightColor::Function.hsla(&theme),
}, },
HighlightedText { HighlightedText {
text: "() {".to_string(), text: "() {".to_string(),
color: HighlightColor::Default.hsla(cx), color: HighlightColor::Default.hsla(&theme),
}, },
], ],
}), }),
@ -399,7 +660,7 @@ pub fn hello_world_rust_buffer_rows(cx: &WindowContext) -> Vec<BufferRow> {
highlighted_texts: vec![HighlightedText { highlighted_texts: vec![HighlightedText {
text: " // Statements here are executed when the compiled binary is called." text: " // Statements here are executed when the compiled binary is called."
.to_string(), .to_string(),
color: HighlightColor::Comment.hsla(cx), color: HighlightColor::Comment.hsla(&theme),
}], }],
}), }),
cursors: None, cursors: None,
@ -422,7 +683,7 @@ pub fn hello_world_rust_buffer_rows(cx: &WindowContext) -> Vec<BufferRow> {
line: Some(HighlightedLine { line: Some(HighlightedLine {
highlighted_texts: vec![HighlightedText { highlighted_texts: vec![HighlightedText {
text: " // Print text to the console.".to_string(), text: " // Print text to the console.".to_string(),
color: HighlightColor::Comment.hsla(cx), color: HighlightColor::Comment.hsla(&theme),
}], }],
}), }),
cursors: None, cursors: None,
@ -433,10 +694,34 @@ pub fn hello_world_rust_buffer_rows(cx: &WindowContext) -> Vec<BufferRow> {
line_number: 5, line_number: 5,
code_action: false, code_action: false,
current: false, current: false,
line: Some(HighlightedLine {
highlighted_texts: vec![
HighlightedText {
text: " println!(".to_string(),
color: HighlightColor::Default.hsla(&theme),
},
HighlightedText {
text: "\"Hello, world!\"".to_string(),
color: HighlightColor::String.hsla(&theme),
},
HighlightedText {
text: ");".to_string(),
color: HighlightColor::Default.hsla(&theme),
},
],
}),
cursors: None,
status: GitStatus::None,
show_line_number,
},
BufferRow {
line_number: 6,
code_action: false,
current: false,
line: Some(HighlightedLine { line: Some(HighlightedLine {
highlighted_texts: vec![HighlightedText { highlighted_texts: vec![HighlightedText {
text: "}".to_string(), text: "}".to_string(),
color: HighlightColor::Default.hsla(cx), color: HighlightColor::Default.hsla(&theme),
}], }],
}), }),
cursors: None, cursors: None,
@ -446,7 +731,36 @@ pub fn hello_world_rust_buffer_rows(cx: &WindowContext) -> Vec<BufferRow> {
] ]
} }
pub fn hello_world_rust_with_status_buffer_rows(cx: &WindowContext) -> Vec<BufferRow> { pub fn hello_world_rust_editor_with_status_example(theme: &Theme) -> Editor {
Editor {
tabs: static_tabs_example(),
path: PathBuf::from_str("crates/ui/src/static_data.rs").unwrap(),
symbols: vec![Symbol(vec![
HighlightedText {
text: "fn ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "main".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
])],
buffer: hello_world_rust_buffer_with_status_example(theme),
}
}
pub fn hello_world_rust_buffer_with_status_example(theme: &Theme) -> Buffer {
Buffer::new()
.set_title("hello_world.rs".to_string())
.set_path("src/hello_world.rs".to_string())
.set_language("rust".to_string())
.set_rows(Some(BufferRows {
show_line_numbers: true,
rows: hello_world_rust_with_status_buffer_rows(theme),
}))
}
pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec<BufferRow> {
let show_line_number = true; let show_line_number = true;
vec![ vec![
@ -458,15 +772,15 @@ pub fn hello_world_rust_with_status_buffer_rows(cx: &WindowContext) -> Vec<Buffe
highlighted_texts: vec![ highlighted_texts: vec![
HighlightedText { HighlightedText {
text: "fn ".to_string(), text: "fn ".to_string(),
color: HighlightColor::Keyword.hsla(cx), color: HighlightColor::Keyword.hsla(&theme),
}, },
HighlightedText { HighlightedText {
text: "main".to_string(), text: "main".to_string(),
color: HighlightColor::Function.hsla(cx), color: HighlightColor::Function.hsla(&theme),
}, },
HighlightedText { HighlightedText {
text: "() {".to_string(), text: "() {".to_string(),
color: HighlightColor::Default.hsla(cx), color: HighlightColor::Default.hsla(&theme),
}, },
], ],
}), }),
@ -482,7 +796,7 @@ pub fn hello_world_rust_with_status_buffer_rows(cx: &WindowContext) -> Vec<Buffe
highlighted_texts: vec![HighlightedText { highlighted_texts: vec![HighlightedText {
text: "// Statements here are executed when the compiled binary is called." text: "// Statements here are executed when the compiled binary is called."
.to_string(), .to_string(),
color: HighlightColor::Comment.hsla(cx), color: HighlightColor::Comment.hsla(&theme),
}], }],
}), }),
cursors: None, cursors: None,
@ -505,7 +819,7 @@ pub fn hello_world_rust_with_status_buffer_rows(cx: &WindowContext) -> Vec<Buffe
line: Some(HighlightedLine { line: Some(HighlightedLine {
highlighted_texts: vec![HighlightedText { highlighted_texts: vec![HighlightedText {
text: " // Print text to the console.".to_string(), text: " // Print text to the console.".to_string(),
color: HighlightColor::Comment.hsla(cx), color: HighlightColor::Comment.hsla(&theme),
}], }],
}), }),
cursors: None, cursors: None,
@ -517,10 +831,20 @@ pub fn hello_world_rust_with_status_buffer_rows(cx: &WindowContext) -> Vec<Buffe
code_action: false, code_action: false,
current: false, current: false,
line: Some(HighlightedLine { line: Some(HighlightedLine {
highlighted_texts: vec![HighlightedText { highlighted_texts: vec![
text: "}".to_string(), HighlightedText {
color: HighlightColor::Default.hsla(cx), text: " println!(".to_string(),
}], color: HighlightColor::Default.hsla(&theme),
},
HighlightedText {
text: "\"Hello, world!\"".to_string(),
color: HighlightColor::String.hsla(&theme),
},
HighlightedText {
text: ");".to_string(),
color: HighlightColor::Default.hsla(&theme),
},
],
}), }),
cursors: None, cursors: None,
status: GitStatus::None, status: GitStatus::None,
@ -532,12 +856,12 @@ pub fn hello_world_rust_with_status_buffer_rows(cx: &WindowContext) -> Vec<Buffe
current: false, current: false,
line: Some(HighlightedLine { line: Some(HighlightedLine {
highlighted_texts: vec![HighlightedText { highlighted_texts: vec![HighlightedText {
text: "".to_string(), text: "}".to_string(),
color: HighlightColor::Default.hsla(cx), color: HighlightColor::Default.hsla(&theme),
}], }],
}), }),
cursors: None, cursors: None,
status: GitStatus::Created, status: GitStatus::None,
show_line_number, show_line_number,
}, },
BufferRow { BufferRow {
@ -546,8 +870,22 @@ pub fn hello_world_rust_with_status_buffer_rows(cx: &WindowContext) -> Vec<Buffe
current: false, current: false,
line: Some(HighlightedLine { line: Some(HighlightedLine {
highlighted_texts: vec![HighlightedText { highlighted_texts: vec![HighlightedText {
text: "Marshall and Nate were here".to_string(), text: "".to_string(),
color: HighlightColor::Default.hsla(cx), color: HighlightColor::Default.hsla(&theme),
}],
}),
cursors: None,
status: GitStatus::Created,
show_line_number,
},
BufferRow {
line_number: 8,
code_action: false,
current: false,
line: Some(HighlightedLine {
highlighted_texts: vec![HighlightedText {
text: "// Marshall and Nate were here".to_string(),
color: HighlightColor::Comment.hsla(&theme),
}], }],
}), }),
cursors: None, cursors: None,
@ -556,3 +894,73 @@ pub fn hello_world_rust_with_status_buffer_rows(cx: &WindowContext) -> Vec<Buffe
}, },
] ]
} }
pub fn terminal_buffer(theme: &Theme) -> Buffer {
Buffer::new()
.set_title("zed — fish".to_string())
.set_rows(Some(BufferRows {
show_line_numbers: false,
rows: terminal_buffer_rows(theme),
}))
}
pub fn terminal_buffer_rows(theme: &Theme) -> Vec<BufferRow> {
let show_line_number = false;
vec![
BufferRow {
line_number: 1,
code_action: false,
current: false,
line: Some(HighlightedLine {
highlighted_texts: vec![
HighlightedText {
text: "maxdeviant ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
HighlightedText {
text: "in ".to_string(),
color: HighlightColor::Default.hsla(&theme),
},
HighlightedText {
text: "profaned-capital ".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
HighlightedText {
text: "in ".to_string(),
color: HighlightColor::Default.hsla(&theme),
},
HighlightedText {
text: "~/p/zed ".to_string(),
color: HighlightColor::Function.hsla(&theme),
},
HighlightedText {
text: "on ".to_string(),
color: HighlightColor::Default.hsla(&theme),
},
HighlightedText {
text: " gpui2-ui ".to_string(),
color: HighlightColor::Keyword.hsla(&theme),
},
],
}),
cursors: None,
status: GitStatus::None,
show_line_number,
},
BufferRow {
line_number: 2,
code_action: false,
current: false,
line: Some(HighlightedLine {
highlighted_texts: vec![HighlightedText {
text: "λ ".to_string(),
color: HighlightColor::String.hsla(&theme),
}],
}),
cursors: None,
status: GitStatus::None,
show_line_number,
},
]
}