From b21c25826dc84dc68eea21033a9775d93412b48c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Nov 2023 15:51:33 +0100 Subject: [PATCH 01/32] Make tab bar visible --- crates/editor2/src/items.rs | 5 ++--- crates/workspace2/src/pane.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/editor2/src/items.rs b/crates/editor2/src/items.rs index c439adcc440f75a559240810db512bd9f9a07874..84263d4ed75042ed398189d16062483162ef71e0 100644 --- a/crates/editor2/src/items.rs +++ b/crates/editor2/src/items.rs @@ -578,12 +578,12 @@ impl Item for Editor { fn tab_content(&self, detail: Option, cx: &AppContext) -> AnyElement { let theme = cx.theme(); + AnyElement::new( div() .flex() .flex_row() .items_center() - .bg(gpui::white()) .text_color(gpui::white()) .child(self.title(cx).to_string()) .children(detail.and_then(|detail| { @@ -625,8 +625,7 @@ impl Item for Editor { fn deactivated(&mut self, cx: &mut ViewContext) { let selection = self.selections.newest_anchor(); - todo!() - // self.push_to_nav_history(selection.head(), None, cx); + self.push_to_nav_history(selection.head(), None, cx); } fn workspace_deactivated(&mut self, cx: &mut ViewContext) { diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index acc41deba880ed986e1391d6fb61d4818ffeef5a..c56defed2667c66d56fe7fdabcd8df6f4a84b2a9 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -1457,7 +1457,7 @@ impl Pane { ), ) .child( - div().w_0().flex_1().h_full().child( + div().flex_1().h_full().child( div().id("tabs").flex().overflow_x_scroll().children( self.items .iter() From 0edcec7c4eee800ebb93d24884d51678cd5ed301 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 3 Nov 2023 09:12:12 -0600 Subject: [PATCH 02/32] Fix tab text colors --- crates/editor2/src/items.rs | 10 ++++++++-- crates/workspace2/src/pane.rs | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/editor2/src/items.rs b/crates/editor2/src/items.rs index 84263d4ed75042ed398189d16062483162ef71e0..a4d34ad36f218af6440ac8183d47c4afca1547df 100644 --- a/crates/editor2/src/items.rs +++ b/crates/editor2/src/items.rs @@ -584,12 +584,18 @@ impl Item for Editor { .flex() .flex_row() .items_center() - .text_color(gpui::white()) + .gap_2() .child(self.title(cx).to_string()) .children(detail.and_then(|detail| { let path = path_for_buffer(&self.buffer, detail, false, cx)?; let description = path.to_string_lossy(); - Some(util::truncate_and_trailoff(&description, MAX_TAB_TITLE_LEN)) + + Some( + div() + .text_color(theme.colors().text_muted) + .text_xs() + .child(util::truncate_and_trailoff(&description, MAX_TAB_TITLE_LEN)), + ) })), ) } diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index c56defed2667c66d56fe7fdabcd8df6f4a84b2a9..eef829afa71596bc0b3c0903ec372af47ab9644f 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -1361,13 +1361,15 @@ impl Pane { let label = item.tab_content(Some(detail), cx); let close_icon = || IconElement::new(Icon::Close).color(IconColor::Muted); - let (tab_bg, tab_hover_bg, tab_active_bg) = match ix == self.active_item_index { + let (text_color, tab_bg, tab_hover_bg, tab_active_bg) = match ix == self.active_item_index { false => ( + cx.theme().colors().text_muted, cx.theme().colors().tab_inactive, cx.theme().colors().ghost_element_hover, cx.theme().colors().ghost_element_active, ), true => ( + cx.theme().colors().text, cx.theme().colors().tab_active, cx.theme().colors().element_hover, cx.theme().colors().element_active, @@ -1397,6 +1399,7 @@ impl Pane { .flex() .items_center() .gap_1p5() + .text_color(text_color) .children(if item.has_conflict(cx) { Some( IconElement::new(Icon::ExclamationTriangle) From b5c2cf371a5c405d122b9a85da8bace4bb7e7dab Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Nov 2023 16:13:23 +0100 Subject: [PATCH 03/32] Ensure panes cover the available space --- crates/workspace2/src/pane.rs | 7 ++++--- crates/workspace2/src/pane_group.rs | 2 +- crates/workspace2/src/status_bar.rs | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index eef829afa71596bc0b3c0903ec372af47ab9644f..1bccaaea6410f46ae1f77a24a4c951ac1abfdc30 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -1891,13 +1891,14 @@ impl Render for Pane { fn render(&mut self, cx: &mut ViewContext) -> Self::Element { v_stack() + .size_full() .child(self.render_tab_bar(cx)) - .child(div() /* toolbar */) + .child(div() /* todo!(toolbar) */) .child(if let Some(item) = self.active_item() { - item.to_any().render() + div().flex_1().child(item.to_any()) } else { // todo!() - div().child("Empty Pane").render() + div().child("Empty Pane") }) // enum MouseNavigationHandler {} diff --git a/crates/workspace2/src/pane_group.rs b/crates/workspace2/src/pane_group.rs index 441aef21f53308924da76d58bea363a202b2ecfa..a9e95b8c29acf604cb7c44e366d6e357257b715e 100644 --- a/crates/workspace2/src/pane_group.rs +++ b/crates/workspace2/src/pane_group.rs @@ -201,7 +201,7 @@ impl Member { // Some(pane) // }; - div().child(pane.clone()).render() + div().size_full().child(pane.clone()).render() // Stack::new() // .with_child(pane_element.contained().with_border(leader_border)) diff --git a/crates/workspace2/src/status_bar.rs b/crates/workspace2/src/status_bar.rs index ca4ebcdb1305bf72b6d04d1409d4c80358ecbab0..4f7ba02c2ae4ae2fbe370941917e4525d7dc0ebb 100644 --- a/crates/workspace2/src/status_bar.rs +++ b/crates/workspace2/src/status_bar.rs @@ -44,6 +44,7 @@ impl Render for StatusBar { .items_center() .justify_between() .w_full() + .h_8() .bg(cx.theme().colors().status_bar) .child(self.render_left_tools(cx)) .child(self.render_right_tools(cx)) From 920ea1bf0a64a679dfebe4cdc611a1b8cb3c008a Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 3 Nov 2023 09:20:13 -0600 Subject: [PATCH 04/32] Make the close button close --- crates/workspace2/src/pane.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index 1bccaaea6410f46ae1f77a24a4c951ac1abfdc30..4c4f26fe0eeb4a8eb53af571cbf2c146edefd2c5 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -1359,7 +1359,16 @@ impl Pane { cx: &mut ViewContext<'_, Pane>, ) -> impl Component { let label = item.tab_content(Some(detail), cx); - let close_icon = || IconElement::new(Icon::Close).color(IconColor::Muted); + let close_icon = || { + let id = item.id(); + div() + .id(item.id()) + .child(IconElement::new(Icon::Close).color(IconColor::Muted)) + .on_click(move |pane: &mut Self, _, cx| { + pane.close_item_by_id(id, SaveIntent::Close, cx) + .detach_and_log_err(cx); + }) + }; let (text_color, tab_bg, tab_hover_bg, tab_active_bg) = match ix == self.active_item_index { false => ( From 580694dbda97cb851e9084290a011cd860ca362f Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 3 Nov 2023 09:56:21 -0600 Subject: [PATCH 05/32] Fix bug when unsubscribe called after remove Co-Authored-By: Julia --- crates/gpui2/src/subscription.rs | 63 ++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/crates/gpui2/src/subscription.rs b/crates/gpui2/src/subscription.rs index 64fcd74dd2a1ab47d4d997d8de52f98fe719c850..744e83bbbddda1a6e6264fa62f81fb23c30f6830 100644 --- a/crates/gpui2/src/subscription.rs +++ b/crates/gpui2/src/subscription.rs @@ -14,7 +14,7 @@ impl Clone for SubscriberSet { } struct SubscriberSetState { - subscribers: BTreeMap>, + subscribers: BTreeMap>>, dropped_subscribers: BTreeSet<(EmitterKey, usize)>, next_subscriber_id: usize, } @@ -38,12 +38,18 @@ where lock.subscribers .entry(emitter_key.clone()) .or_default() + .insert(Default::default()) .insert(subscriber_id, callback); let this = self.0.clone(); Subscription { unsubscribe: Some(Box::new(move || { let mut lock = this.lock(); - if let Some(subscribers) = lock.subscribers.get_mut(&emitter_key) { + let Some(subscribers) = lock.subscribers.get_mut(&emitter_key) else { + // remove was called with this emitter_key + return; + }; + + if let Some(subscribers) = subscribers { subscribers.remove(&subscriber_id); if subscribers.is_empty() { lock.subscribers.remove(&emitter_key); @@ -62,34 +68,43 @@ where pub fn remove(&self, emitter: &EmitterKey) -> impl IntoIterator { let subscribers = self.0.lock().subscribers.remove(&emitter); - subscribers.unwrap_or_default().into_values() + subscribers + .unwrap_or_default() + .map(|s| s.into_values()) + .into_iter() + .flatten() } pub fn retain(&self, emitter: &EmitterKey, mut f: F) where F: FnMut(&mut Callback) -> bool, { - let entry = self.0.lock().subscribers.remove_entry(emitter); - if let Some((emitter, mut subscribers)) = entry { - subscribers.retain(|_, callback| f(callback)); - let mut lock = self.0.lock(); - - // Add any new subscribers that were added while invoking the callback. - if let Some(new_subscribers) = lock.subscribers.remove(&emitter) { - subscribers.extend(new_subscribers); - } - - // Remove any dropped subscriptions that were dropped while invoking the callback. - for (dropped_emitter, dropped_subscription_id) in - mem::take(&mut lock.dropped_subscribers) - { - debug_assert_eq!(emitter, dropped_emitter); - subscribers.remove(&dropped_subscription_id); - } - - if !subscribers.is_empty() { - lock.subscribers.insert(emitter, subscribers); - } + let Some(mut subscribers) = self + .0 + .lock() + .subscribers + .get_mut(emitter) + .and_then(|s| s.take()) + else { + return; + }; + + subscribers.retain(|_, callback| f(callback)); + let mut lock = self.0.lock(); + + // Add any new subscribers that were added while invoking the callback. + if let Some(Some(new_subscribers)) = lock.subscribers.remove(&emitter) { + subscribers.extend(new_subscribers); + } + + // Remove any dropped subscriptions that were dropped while invoking the callback. + for (dropped_emitter, dropped_subscription_id) in mem::take(&mut lock.dropped_subscribers) { + debug_assert_eq!(*emitter, dropped_emitter); + subscribers.remove(&dropped_subscription_id); + } + + if !subscribers.is_empty() { + lock.subscribers.insert(emitter.clone(), Some(subscribers)); } } } From d3b02c4de47c80bd3a7bb544e75c7e347c0f3839 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Nov 2023 17:14:11 +0100 Subject: [PATCH 06/32] WIP: start on editor element --- crates/editor2/src/editor.rs | 92 ++++++------ crates/editor2/src/element.rs | 181 +++++++++++++++++++----- crates/editor2/src/scroll.rs | 28 ++-- crates/editor2/src/scroll/autoscroll.rs | 6 +- crates/gpui2/src/geometry.rs | 6 + 5 files changed, 217 insertions(+), 96 deletions(-) diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index ea747de5de689e6050581aecd5a618acd79ef9a5..52628f61b58c9ee4411321266c6789b02b98a465 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -37,8 +37,8 @@ use futures::FutureExt; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ div, AnyElement, AppContext, BackgroundExecutor, Context, Div, Element, EventEmitter, - FocusHandle, Hsla, Model, Pixels, Render, Subscription, Task, TextStyle, View, ViewContext, - VisualContext, WeakView, WindowContext, + FocusHandle, Hsla, Model, Pixels, Render, Styled, Subscription, Task, TextStyle, View, + ViewContext, VisualContext, WeakView, WindowContext, }; use highlight_matching_bracket::refresh_matching_bracket_highlights; use hover_popover::{hide_hover, HoverState}; @@ -68,6 +68,7 @@ use scroll::{ use selections_collection::{MutableSelectionsCollection, SelectionsCollection}; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsStore}; +use smallvec::SmallVec; use std::{ any::TypeId, borrow::Cow, @@ -8347,51 +8348,51 @@ impl Editor { // .text() // } - // pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> { - // let mut wrap_guides = smallvec::smallvec![]; + pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> { + let mut wrap_guides = smallvec::smallvec![]; - // if self.show_wrap_guides == Some(false) { - // return wrap_guides; - // } + if self.show_wrap_guides == Some(false) { + return wrap_guides; + } - // let settings = self.buffer.read(cx).settings_at(0, cx); - // if settings.show_wrap_guides { - // if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) { - // wrap_guides.push((soft_wrap as usize, true)); - // } - // wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false))) - // } + let settings = self.buffer.read(cx).settings_at(0, cx); + if settings.show_wrap_guides { + if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) { + wrap_guides.push((soft_wrap as usize, true)); + } + wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false))) + } - // wrap_guides - // } + wrap_guides + } - // pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap { - // let settings = self.buffer.read(cx).settings_at(0, cx); - // let mode = self - // .soft_wrap_mode_override - // .unwrap_or_else(|| settings.soft_wrap); - // match mode { - // language_settings::SoftWrap::None => SoftWrap::None, - // language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth, - // language_settings::SoftWrap::PreferredLineLength => { - // SoftWrap::Column(settings.preferred_line_length) - // } - // } - // } + pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap { + let settings = self.buffer.read(cx).settings_at(0, cx); + let mode = self + .soft_wrap_mode_override + .unwrap_or_else(|| settings.soft_wrap); + match mode { + language_settings::SoftWrap::None => SoftWrap::None, + language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth, + language_settings::SoftWrap::PreferredLineLength => { + SoftWrap::Column(settings.preferred_line_length) + } + } + } - // pub fn set_soft_wrap_mode( - // &mut self, - // mode: language_settings::SoftWrap, - // cx: &mut ViewContext, - // ) { - // self.soft_wrap_mode_override = Some(mode); - // cx.notify(); - // } + pub fn set_soft_wrap_mode( + &mut self, + mode: language_settings::SoftWrap, + cx: &mut ViewContext, + ) { + self.soft_wrap_mode_override = Some(mode); + cx.notify(); + } - // pub fn set_wrap_width(&self, width: Option, cx: &mut AppContext) -> bool { - // self.display_map - // .update(cx, |map, cx| map.set_wrap_width(width, cx)) - // } + pub fn set_wrap_width(&self, width: Option, cx: &mut AppContext) -> bool { + self.display_map + .update(cx, |map, cx| map.set_wrap_width(width, cx)) + } // pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext) { // if self.soft_wrap_mode_override.is_some() { @@ -9321,11 +9322,14 @@ impl EventEmitter for Editor { } impl Render for Editor { - type Element = Div; + type Element = EditorElement; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { - // todo!() - div() + EditorElement::new(EditorStyle { + text: cx.text_style(), + line_height_scalar: 1., + theme_id: 0, + }) } } diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index 645cdc76469e1db52c898036a49f960aa0bfee67..6420d1e6cd6482ac99e79f3de0dfbd3c2963359c 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -3,17 +3,18 @@ use super::{ }; use crate::{ display_map::{BlockStyle, DisplaySnapshot}, - EditorStyle, + EditorMode, EditorStyle, SoftWrap, }; use anyhow::Result; use gpui::{ - black, px, relative, AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style, TextRun, - TextSystem, + black, point, px, relative, size, AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style, + TextRun, TextSystem, ViewContext, }; use language::{CursorShape, Selection}; use smallvec::SmallVec; -use std::{ops::Range, sync::Arc}; +use std::{cmp, ops::Range, sync::Arc}; use sum_tree::Bias; +use theme::ActiveTheme; enum FoldMarkers {} @@ -1321,29 +1322,31 @@ impl EditorElement { // } // } - // fn column_pixels(&self, column: usize, cx: &ViewContext) -> f32 { - // let style = &self.style; - - // cx.text_layout_cache() - // .layout_str( - // " ".repeat(column).as_str(), - // style.text.font_size, - // &[( - // column, - // RunStyle { - // font_id: style.text.font_id, - // color: Color::black(), - // underline: Default::default(), - // }, - // )], - // ) - // .width() - // } + fn column_pixels(&self, column: usize, cx: &ViewContext) -> Pixels { + let style = &self.style; + let font_size = style.text.font_size * cx.rem_size(); + let layout = cx + .text_system() + .layout_text( + " ".repeat(column).as_str(), + font_size, + &[TextRun { + len: column, + font: style.text.font(), + color: Hsla::default(), + underline: None, + }], + None, + ) + .unwrap(); + + layout[0].width + } - // fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext) -> f32 { - // let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1; - // self.column_pixels(digit_count, cx) - // } + fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext) -> Pixels { + let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1; + self.column_pixels(digit_count, cx) + } //Folds contained in a hunk are ignored apart from shrinking visual size //If a fold contains any hunks then that fold line is marked as modified @@ -2002,6 +2005,7 @@ impl Element for EditorElement { element_state: &mut Self::ElementState, cx: &mut gpui::ViewContext, ) -> gpui::LayoutId { + let rem_size = cx.rem_size(); let mut style = Style::default(); style.size.width = relative(1.).into(); style.size.height = relative(1.).into(); @@ -2011,18 +2015,125 @@ impl Element for EditorElement { fn paint( &mut self, bounds: Bounds, - view_state: &mut Editor, + editor: &mut Editor, element_state: &mut Self::ElementState, cx: &mut gpui::ViewContext, ) { - let text_style = cx.text_style(); - - let layout_text = cx.text_system().layout_text( - "hello world", - text_style.font_size * cx.rem_size(), - &[text_style.to_run("hello world".len())], - None, - ); + // let mut size = constraint.max; + // if size.x().is_infinite() { + // unimplemented!("we don't yet handle an infinite width constraint on buffer elements"); + // } + + let snapshot = editor.snapshot(cx); + let style = self.style.clone(); + let font_id = cx.text_system().font_id(&style.text.font()).unwrap(); + let font_size = style.text.font_size * cx.rem_size(); + let line_height = (font_size * style.line_height_scalar).round(); + let em_width = cx + .text_system() + .typographic_bounds(font_id, font_size, 'm') + .unwrap() + .size + .width; + let em_advance = cx + .text_system() + .advance(font_id, font_size, 'm') + .unwrap() + .width; + + let gutter_padding; + let gutter_width; + let gutter_margin; + if snapshot.show_gutter { + let descent = cx.text_system().descent(font_id, font_size).unwrap(); + + let gutter_padding_factor = 3.5; + gutter_padding = (em_width * gutter_padding_factor).round(); + gutter_width = self.max_line_number_width(&snapshot, cx) + gutter_padding * 2.0; + gutter_margin = -descent; + } else { + gutter_padding = px(0.0); + gutter_width = px(0.0); + gutter_margin = px(0.0); + }; + + let text_width = bounds.size.width - gutter_width; + let overscroll = point(em_width, px(0.)); + let snapshot = { + editor.set_visible_line_count((bounds.size.height / line_height).into(), cx); + + let editor_width = text_width - gutter_margin - overscroll.x - em_width; + let wrap_width = match editor.soft_wrap_mode(cx) { + SoftWrap::None => (MAX_LINE_LEN / 2) as f32 * em_advance, + SoftWrap::EditorWidth => editor_width, + SoftWrap::Column(column) => editor_width.min(column as f32 * em_advance), + }; + + if editor.set_wrap_width(Some(wrap_width), cx) { + editor.snapshot(cx) + } else { + snapshot + } + }; + + let wrap_guides = editor + .wrap_guides(cx) + .iter() + .map(|(guide, active)| (self.column_pixels(*guide, cx), *active)) + .collect::>(); + + let scroll_height = Pixels::from(snapshot.max_point().row() + 1) * line_height; + // todo!("this should happen during layout") + if let EditorMode::AutoHeight { max_lines } = snapshot.mode { + todo!() + // size.set_y( + // scroll_height + // .min(constraint.max_along(Axis::Vertical)) + // .max(constraint.min_along(Axis::Vertical)) + // .max(line_height) + // .min(line_height * max_lines as f32), + // ) + } else if let EditorMode::SingleLine = snapshot.mode { + todo!() + // size.set_y(line_height.max(constraint.min_along(Axis::Vertical))) + } + // todo!() + // else if size.y().is_infinite() { + // // size.set_y(scroll_height); + // } + // + let gutter_size = size(gutter_width, bounds.size.height); + let text_size = size(text_width, bounds.size.height); + + let autoscroll_horizontally = + editor.autoscroll_vertically(bounds.size.height, line_height, cx); + let mut snapshot = editor.snapshot(cx); + + let scroll_position = snapshot.scroll_position(); + // The scroll position is a fractional point, the whole number of which represents + // the top of the window in terms of display rows. + let start_row = scroll_position.y as u32; + let height_in_lines = f32::from(bounds.size.height / line_height); + let max_row = snapshot.max_point().row(); + + // Add 1 to ensure selections bleed off screen + let end_row = 1 + cmp::min((scroll_position.y + height_in_lines).ceil() as u32, max_row); + + dbg!(start_row..end_row); + // let text_style = cx.text_style(); + // let layout_text = cx.text_system().layout_text( + // "hello world", + // text_style.font_size * cx.rem_size(), + // &[text_style.to_run("hello world".len())], + // None, + // ); + // let line_height = text_style + // .line_height + // .to_pixels(text_style.font_size.into(), cx.rem_size()); + + // layout_text.unwrap()[0] + // .paint(bounds.origin, line_height, cx) + // .unwrap(); } } diff --git a/crates/editor2/src/scroll.rs b/crates/editor2/src/scroll.rs index 5e4b32265a221cb2561134776fac7bb3fc266931..1876952ae2fa773dcd03277cfdff85d3ffd0d9e9 100644 --- a/crates/editor2/src/scroll.rs +++ b/crates/editor2/src/scroll.rs @@ -303,20 +303,20 @@ impl Editor { self.scroll_manager.visible_line_count } - // pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext) { - // let opened_first_time = self.scroll_manager.visible_line_count.is_none(); - // self.scroll_manager.visible_line_count = Some(lines); - // if opened_first_time { - // cx.spawn(|editor, mut cx| async move { - // editor - // .update(&mut cx, |editor, cx| { - // editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx) - // }) - // .ok() - // }) - // .detach() - // } - // } + pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext) { + let opened_first_time = self.scroll_manager.visible_line_count.is_none(); + self.scroll_manager.visible_line_count = Some(lines); + if opened_first_time { + cx.spawn(|editor, mut cx| async move { + editor + .update(&mut cx, |editor, cx| { + editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx) + }) + .ok() + }) + .detach() + } + } pub fn set_scroll_position( &mut self, diff --git a/crates/editor2/src/scroll/autoscroll.rs b/crates/editor2/src/scroll/autoscroll.rs index a4c37a258e982b6099611ac548f4802b3437b897..9315d5c0997fd649e8c0f16cc5425cca1803a8f4 100644 --- a/crates/editor2/src/scroll/autoscroll.rs +++ b/crates/editor2/src/scroll/autoscroll.rs @@ -48,11 +48,11 @@ impl AutoscrollStrategy { impl Editor { pub fn autoscroll_vertically( &mut self, - viewport_height: f32, - line_height: f32, + viewport_height: Pixels, + line_height: Pixels, cx: &mut ViewContext, ) -> bool { - let visible_lines = viewport_height / line_height; + let visible_lines = f32::from(viewport_height / line_height); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut scroll_position = self.scroll_manager.scroll_position(&display_map); let max_scroll_top = if matches!(self.mode, EditorMode::AutoHeight { .. }) { diff --git a/crates/gpui2/src/geometry.rs b/crates/gpui2/src/geometry.rs index b2fad4efda9e127ce74c319ac2471cf24798a247..081b11aae0e250237e091bf8ab7ecc565e57c960 100644 --- a/crates/gpui2/src/geometry.rs +++ b/crates/gpui2/src/geometry.rs @@ -825,6 +825,12 @@ impl From for u32 { } } +impl From for Pixels { + fn from(pixels: u32) -> Self { + Pixels(pixels as f32) + } +} + impl From for usize { fn from(pixels: Pixels) -> Self { pixels.0 as usize From c604a2e34e8b26dd3780de0a250b0e5bf8bbba7b Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 3 Nov 2023 10:54:26 -0600 Subject: [PATCH 07/32] Add hover behaviour to tabs Co-Authored-By: Marshall Co-Authored-By: Nathan --- crates/gpui2/src/element.rs | 13 +++++++++++++ crates/gpui2/src/elements/div.rs | 8 ++++++-- crates/gpui2/src/style.rs | 11 +++++++++++ crates/gpui2/src/styled.rs | 21 +++++++++++++++++++++ crates/ui2/src/elements/icon.rs | 13 +++++++++++-- crates/workspace2/src/pane.rs | 10 +++++++++- 6 files changed, 71 insertions(+), 5 deletions(-) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index a92dbd6ff94a98165f5b200bc4eadedb2471bf5a..2a0f557272f4899eb21f2bbb3123a08045a56158 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -212,6 +212,19 @@ pub trait Component { { self.map(|this| if condition { then(this) } else { this }) } + + fn when_some(self, option: Option, then: impl FnOnce(Self, T) -> Self) -> Self + where + Self: Sized, + { + self.map(|this| { + if let Some(value) = option { + then(this, value) + } else { + this + } + }) + } } impl Component for AnyElement { diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 56940efce4a0982c4255b613f682137ed3ce1582..bf28ec3bf5ffffe1b6bd3db9d0fe306c6ce7b7fb 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -3,7 +3,7 @@ use crate::{ ElementInteraction, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable, GlobalElementId, GroupBounds, InteractiveElementState, LayoutId, Overflow, ParentElement, Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction, - StatelessInteractive, Style, StyleRefinement, Styled, ViewContext, + StatelessInteractive, Style, StyleRefinement, Styled, ViewContext, Visibility, }; use refineable::Refineable; use smallvec::SmallVec; @@ -249,11 +249,15 @@ where cx: &mut ViewContext, ) { self.with_element_id(cx, |this, _global_id, cx| { + let style = this.compute_style(bounds, element_state, cx); + if style.visibility == Visibility::Hidden { + return; + } + if let Some(group) = this.group.clone() { GroupBounds::push(group, bounds, cx); } - let style = this.compute_style(bounds, element_state, cx); let z_index = style.z_index.unwrap_or(0); let mut child_min = point(Pixels::MAX, Pixels::MAX); diff --git a/crates/gpui2/src/style.rs b/crates/gpui2/src/style.rs index b30d4aa00250f981f48301f6e3c8007b55b1bb36..b3cd5c478b3ba111816ec8c44afd5e63b8f9b1a0 100644 --- a/crates/gpui2/src/style.rs +++ b/crates/gpui2/src/style.rs @@ -19,6 +19,9 @@ pub struct Style { /// What layout strategy should be used? pub display: Display, + /// Should the element be painted on screen? + pub visibility: Visibility, + // Overflow properties /// How children overflowing their container should affect layout #[refineable] @@ -107,6 +110,13 @@ impl Styled for StyleRefinement { } } +#[derive(Default, Clone, Copy, Debug, Eq, PartialEq)] +pub enum Visibility { + #[default] + Visible, + Hidden, +} + #[derive(Clone, Debug)] pub struct BoxShadow { pub color: Hsla, @@ -297,6 +307,7 @@ impl Default for Style { fn default() -> Self { Style { display: Display::Block, + visibility: Visibility::Visible, overflow: Point { x: Overflow::Visible, y: Overflow::Visible, diff --git a/crates/gpui2/src/styled.rs b/crates/gpui2/src/styled.rs index 1eed74f0969a437ae3827815345b10962091f6fb..a88a8b4d6f85c63cb49e9a762196f4205c24a5c8 100644 --- a/crates/gpui2/src/styled.rs +++ b/crates/gpui2/src/styled.rs @@ -1,6 +1,7 @@ use crate::{ self as gpui2, hsla, point, px, relative, rems, AlignItems, DefiniteLength, Display, Fill, FlexDirection, Hsla, JustifyContent, Length, Position, Rems, SharedString, StyleRefinement, + Visibility, }; use crate::{BoxShadow, TextStyleRefinement}; use smallvec::smallvec; @@ -60,6 +61,26 @@ pub trait Styled { self } + /// Sets the visibility of the element to `visible`. + /// [Docs](https://tailwindcss.com/docs/visibility) + fn visible(mut self) -> Self + where + Self: Sized, + { + self.style().visibility = Some(Visibility::Visible); + self + } + + /// Sets the visibility of the element to `hidden`. + /// [Docs](https://tailwindcss.com/docs/visibility) + fn invisible(mut self) -> Self + where + Self: Sized, + { + self.style().visibility = Some(Visibility::Hidden); + self + } + /// Sets the flex direction of the element to `column`. /// [Docs](https://tailwindcss.com/docs/flex-direction#column) fn flex_col(mut self) -> Self diff --git a/crates/ui2/src/elements/icon.rs b/crates/ui2/src/elements/icon.rs index 5885d76101f18ce332e418423afb0f2d1f3d0da8..94e15ca0f1187dcc8851619fa7d94f0b295300c8 100644 --- a/crates/ui2/src/elements/icon.rs +++ b/crates/ui2/src/elements/icon.rs @@ -159,6 +159,7 @@ impl Icon { pub struct IconElement { icon: Icon, color: IconColor, + hover_color: Option, size: IconSize, } @@ -167,6 +168,7 @@ impl IconElement { Self { icon, color: IconColor::default(), + hover_color: None, size: IconSize::default(), } } @@ -176,13 +178,17 @@ impl IconElement { self } + pub fn hover_color(mut self, hover_color: impl Into>) -> Self { + self.hover_color = hover_color.into(); + self + } + pub fn size(mut self, size: IconSize) -> Self { self.size = size; self } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let fill = self.color.color(cx); let svg_size = match self.size { IconSize::Small => rems(0.75), IconSize::Medium => rems(0.9375), @@ -192,7 +198,10 @@ impl IconElement { .size(svg_size) .flex_none() .path(self.icon.path()) - .text_color(fill) + .text_color(self.color.color(cx)) + .when_some(self.hover_color, |this, hover_color| { + this.hover(|style| style.text_color(hover_color.color(cx))) + }) } } diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index 4c4f26fe0eeb4a8eb53af571cbf2c146edefd2c5..f8e3c02178963204ca004cc2ef79405e11cc84f6 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -1361,9 +1361,16 @@ impl Pane { let label = item.tab_content(Some(detail), cx); let close_icon = || { let id = item.id(); + div() .id(item.id()) - .child(IconElement::new(Icon::Close).color(IconColor::Muted)) + .invisible() + .group_hover("", |style| style.visible()) + .child( + IconElement::new(Icon::Close) + .color(IconColor::Muted) + .hover_color(IconColor::Accent), + ) .on_click(move |pane: &mut Self, _, cx| { pane.close_item_by_id(id, SaveIntent::Close, cx) .detach_and_log_err(cx); @@ -1388,6 +1395,7 @@ impl Pane { let close_right = ItemSettings::get_global(cx).close_position.right(); div() + .group("") .id(item.id()) // .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx)) // .drag_over::(|d| d.bg(cx.theme().colors().element_drop_target)) From d73c54f6049aeef161e6673eeabeedea2918b830 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 3 Nov 2023 11:30:15 -0600 Subject: [PATCH 08/32] Add PointingHand on tabs --- crates/gpui2/src/elements/div.rs | 7 +++++++ crates/gpui2/src/style.rs | 10 +++++++--- crates/gpui2/src/styled.rs | 34 +++++++++++++++++++++++++++++--- crates/gpui2/src/window.rs | 31 ++++++++++++++++++++--------- crates/workspace2/src/pane.rs | 6 ++++-- crates/zed2/src/main.rs | 1 - 6 files changed, 71 insertions(+), 18 deletions(-) diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index bf28ec3bf5ffffe1b6bd3db9d0fe306c6ce7b7fb..e011041bae2259f8a290ef098b061740721f4307 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -254,6 +254,13 @@ where return; } + if let Some(mouse_cursor) = style.mouse_cursor { + let hovered = bounds.contains_point(&cx.mouse_position()); + if hovered { + cx.set_cursor_style(mouse_cursor); + } + } + if let Some(group) = this.group.clone() { GroupBounds::push(group, bounds, cx); } diff --git a/crates/gpui2/src/style.rs b/crates/gpui2/src/style.rs index b3cd5c478b3ba111816ec8c44afd5e63b8f9b1a0..d2571a3253522cbfed12ffce1d130d762ac59a5a 100644 --- a/crates/gpui2/src/style.rs +++ b/crates/gpui2/src/style.rs @@ -1,8 +1,8 @@ use crate::{ black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, - Corners, CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, - FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rems, Result, Rgba, - SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext, WindowContext, + Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font, + FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rems, + Result, Rgba, SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext, WindowContext, }; use refineable::{Cascade, Refineable}; use smallvec::SmallVec; @@ -101,6 +101,9 @@ pub struct Style { /// TEXT pub text: TextStyleRefinement, + /// The mouse cursor style shown when the mouse pointer is over an element. + pub mouse_cursor: Option, + pub z_index: Option, } @@ -339,6 +342,7 @@ impl Default for Style { corner_radii: Corners::default(), box_shadow: Default::default(), text: TextStyleRefinement::default(), + mouse_cursor: None, z_index: None, } } diff --git a/crates/gpui2/src/styled.rs b/crates/gpui2/src/styled.rs index a88a8b4d6f85c63cb49e9a762196f4205c24a5c8..4a9a5d7ecf0c1fc18791dd5be596f4bfc488c7b4 100644 --- a/crates/gpui2/src/styled.rs +++ b/crates/gpui2/src/styled.rs @@ -1,7 +1,7 @@ use crate::{ - self as gpui2, hsla, point, px, relative, rems, AlignItems, DefiniteLength, Display, Fill, - FlexDirection, Hsla, JustifyContent, Length, Position, Rems, SharedString, StyleRefinement, - Visibility, + self as gpui2, hsla, point, px, relative, rems, AlignItems, CursorStyle, DefiniteLength, + Display, Fill, FlexDirection, Hsla, JustifyContent, Length, Position, Rems, SharedString, + StyleRefinement, Visibility, }; use crate::{BoxShadow, TextStyleRefinement}; use smallvec::smallvec; @@ -81,6 +81,34 @@ pub trait Styled { self } + fn cursor(mut self, cursor: CursorStyle) -> Self + where + Self: Sized, + { + self.style().mouse_cursor = Some(cursor); + self + } + + /// Sets the cursor style when hovering an element to `default`. + /// [Docs](https://tailwindcss.com/docs/cursor) + fn cursor_default(mut self) -> Self + where + Self: Sized, + { + self.style().mouse_cursor = Some(CursorStyle::Arrow); + self + } + + /// Sets the cursor style when hovering an element to `pointer`. + /// [Docs](https://tailwindcss.com/docs/cursor) + fn cursor_pointer(mut self) -> Self + where + Self: Sized, + { + self.style().mouse_cursor = Some(CursorStyle::PointingHand); + self + } + /// Sets the flex direction of the element to `column`. /// [Docs](https://tailwindcss.com/docs/flex-direction#column) fn flex_col(mut self) -> Self diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 2284f3ccc2269c21fe55a32b3ad3d1f4b1b3ca4a..e998766bbb8126ac62b99ac2611caec72a941dc6 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1,14 +1,14 @@ use crate::{ px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, - Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, - Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, - Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, - Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, - MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformWindow, Point, - PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams, - RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet, - Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, - WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS, + Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels, DispatchContext, DisplayId, + Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, + GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, + KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, + MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, + PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, + RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, + Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, + VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::{anyhow, Result}; use collections::HashMap; @@ -190,6 +190,7 @@ pub struct Window { pub(crate) focus_handles: Arc>>, default_prevented: bool, mouse_position: Point, + requested_cursor_style: Option, scale_factor: f32, bounds: WindowBounds, bounds_observers: SubscriberSet<(), AnyObserver>, @@ -283,6 +284,7 @@ impl Window { focus_handles: Arc::new(RwLock::new(SlotMap::with_key())), default_prevented: true, mouse_position, + requested_cursor_style: None, scale_factor, bounds, bounds_observers: SubscriberSet::new(), @@ -669,6 +671,10 @@ impl<'a> WindowContext<'a> { self.window.mouse_position } + pub fn set_cursor_style(&mut self, style: CursorStyle) { + self.window.requested_cursor_style = Some(style) + } + /// Called during painting to invoke the given closure in a new stacking context. The given /// z-index is interpreted relative to the previous call to `stack`. pub fn stack(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R { @@ -987,6 +993,13 @@ impl<'a> WindowContext<'a> { let scene = self.window.scene_builder.build(); self.window.platform_window.draw(scene); + let cursor_style = self + .window + .requested_cursor_style + .take() + .unwrap_or(CursorStyle::Arrow); + self.platform.set_cursor_style(cursor_style); + self.window.dirty = false; } diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index f8e3c02178963204ca004cc2ef79405e11cc84f6..4d5b96ea6d201764f3fd1ee6f09bccf0bc3f1019 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -9,8 +9,9 @@ use crate::{ use anyhow::Result; use collections::{HashMap, HashSet, VecDeque}; use gpui::{ - AppContext, AsyncWindowContext, Component, Div, EntityId, EventEmitter, FocusHandle, Model, - PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, WindowContext, + AppContext, AsyncWindowContext, Component, CursorStyle, Div, EntityId, EventEmitter, + FocusHandle, Model, PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, + WindowContext, }; use parking_lot::Mutex; use project2::{Project, ProjectEntryId, ProjectPath}; @@ -1397,6 +1398,7 @@ impl Pane { div() .group("") .id(item.id()) + .cursor_pointer() // .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx)) // .drag_over::(|d| d.bg(cx.theme().colors().element_drop_target)) // .on_drop(|_view, state: View, cx| { diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index 79ba132e4ffedaa275d1c3cbdb64cf3692970b13..52eb512eb4e4c47850031689f13f336f89488b6b 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -208,7 +208,6 @@ fn main() { if stdout_is_a_pty() { cx.activate(true); let urls = collect_url_args(); - dbg!(&urls); if !urls.is_empty() { listener.open_urls(urls) } From 26e64fb84385bc1d6f3f531a60fc1472b51989d4 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 3 Nov 2023 12:51:38 -0600 Subject: [PATCH 09/32] gpui2: Add on_hover events --- crates/gpui2/src/interactive.rs | 60 +++++++++++++++++++++++++++++++++ crates/workspace2/src/pane.rs | 4 +++ 2 files changed, 64 insertions(+) diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index 020cb82cd2a26bf7a011b44db7dd78711c386024..7966b68e121c7882e9f32bb219ac07cefeed0f22 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -333,6 +333,37 @@ pub trait StatefulInteractive: StatelessInteractive { })); self } + + fn on_hover(mut self, listener: impl 'static + Fn(&mut V, bool, &mut ViewContext)) -> Self + where + Self: Sized, + { + debug_assert!( + self.stateful_interaction().hover_listener.is_none(), + "calling on_hover more than once on the same element is not supported" + ); + self.stateful_interaction().hover_listener = Some(Box::new(listener)); + self + } + + fn tooltip( + mut self, + build_tooltip: impl Fn(&mut V, &mut ViewContext) -> View + 'static, + ) -> Self + where + Self: Sized, + W: 'static + Render, + { + debug_assert!( + self.stateful_interaction().tooltip_builder.is_none(), + "calling tooltip more than once on the same element is not supported" + ); + self.stateful_interaction().tooltip_builder = Some(Box::new(move |view_state, cx| { + build_tooltip(view_state, cx).into() + })); + + self + } } pub trait ElementInteraction: 'static { @@ -568,6 +599,24 @@ pub trait ElementInteraction: 'static { } } + if let Some(hover_listener) = stateful.hover_listener.take() { + let was_hovered = element_state.hover_state.clone(); + let has_mouse_down = element_state.pending_mouse_down.lock().is_some(); + cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| { + if phase != DispatchPhase::Bubble { + return; + } + let is_hovered = bounds.contains_point(&event.position) && !has_mouse_down; + let mut was_hovered = was_hovered.lock(); + + if is_hovered != was_hovered.clone() { + *was_hovered = is_hovered; + drop(was_hovered); + hover_listener(view_state, is_hovered, cx); + } + }); + } + let active_state = element_state.active_state.clone(); if active_state.lock().is_none() { let active_group_bounds = stateful @@ -639,6 +688,8 @@ pub struct StatefulInteraction { active_style: StyleRefinement, group_active_style: Option, drag_listener: Option>, + hover_listener: Option>, + tooltip_builder: Option>, } impl ElementInteraction for StatefulInteraction { @@ -666,6 +717,8 @@ impl From for StatefulInteraction { stateless: StatelessInteraction::default(), click_listeners: SmallVec::new(), drag_listener: None, + hover_listener: None, + tooltip_builder: None, active_style: StyleRefinement::default(), group_active_style: None, } @@ -695,6 +748,8 @@ impl StatelessInteraction { stateless: self, click_listeners: SmallVec::new(), drag_listener: None, + hover_listener: None, + tooltip_builder: None, active_style: StyleRefinement::default(), group_active_style: None, } @@ -746,6 +801,7 @@ impl ActiveState { #[derive(Default)] pub struct InteractiveElementState { active_state: Arc>, + hover_state: Arc>, pending_mouse_down: Arc>>, scroll_offset: Option>>>, } @@ -1097,6 +1153,10 @@ pub type ClickListener = Box) pub(crate) type DragListener = Box, &mut ViewContext) -> AnyDrag + 'static>; +pub(crate) type HoverListener = Box) + 'static>; + +pub(crate) type TooltipBuilder = Box) -> AnyView + 'static>; + pub type KeyListener = Box< dyn Fn( &mut V, diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index 4d5b96ea6d201764f3fd1ee6f09bccf0bc3f1019..acda04c5a47cbf147ef1fac3d54c900be7eb5614 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -1399,6 +1399,10 @@ impl Pane { .group("") .id(item.id()) .cursor_pointer() + .on_hover(|_, hovered, _| { + dbg!(hovered); + }) + // .tooltip(|pane, cx| cx.create_view( tooltip.child("Hovering the tab")) // .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx)) // .drag_over::(|d| d.bg(cx.theme().colors().element_drop_target)) // .on_drop(|_view, state: View, cx| { From 33245d119e24063ed2732d138e58c296cd5518ca Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 3 Nov 2023 14:02:46 -0600 Subject: [PATCH 10/32] Tooltip on tabs Co-Authored-By: Julia --- crates/gpui2/src/app.rs | 2 ++ crates/gpui2/src/interactive.rs | 24 +++++++++++++++++-- crates/gpui2/src/window.rs | 8 +++++++ crates/ui2/src/components.rs | 2 ++ crates/ui2/src/components/tooltip.rs | 36 ++++++++++++++++++++++++++++ crates/workspace2/src/pane.rs | 12 ++++++---- 6 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 crates/ui2/src/components/tooltip.rs diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 9ec76a86d4e7bd0726cc1a38f98a942728c7e43d..974395e8971f92a3524a5a8177f792a567b88904 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -157,6 +157,7 @@ pub struct AppContext { flushing_effects: bool, pending_updates: usize, pub(crate) active_drag: Option, + pub(crate) active_tooltip: Option, pub(crate) next_frame_callbacks: HashMap>, pub(crate) frame_consumers: HashMap>, pub(crate) background_executor: BackgroundExecutor, @@ -215,6 +216,7 @@ impl AppContext { flushing_effects: false, pending_updates: 0, active_drag: None, + active_tooltip: None, next_frame_callbacks: HashMap::default(), frame_consumers: HashMap::default(), background_executor: executor, diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index 7966b68e121c7882e9f32bb219ac07cefeed0f22..def7315a7cca6fe8cd3c7b9376438218cb226852 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -358,7 +358,7 @@ pub trait StatefulInteractive: StatelessInteractive { self.stateful_interaction().tooltip_builder.is_none(), "calling tooltip more than once on the same element is not supported" ); - self.stateful_interaction().tooltip_builder = Some(Box::new(move |view_state, cx| { + self.stateful_interaction().tooltip_builder = Some(Arc::new(move |view_state, cx| { build_tooltip(view_state, cx).into() })); @@ -602,6 +602,10 @@ pub trait ElementInteraction: 'static { if let Some(hover_listener) = stateful.hover_listener.take() { let was_hovered = element_state.hover_state.clone(); let has_mouse_down = element_state.pending_mouse_down.lock().is_some(); + + let active_tooltip = element_state.active_tooltip.clone(); + let tooltip_builder = stateful.tooltip_builder.clone(); + cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; @@ -612,11 +616,26 @@ pub trait ElementInteraction: 'static { if is_hovered != was_hovered.clone() { *was_hovered = is_hovered; drop(was_hovered); + if let Some(tooltip_builder) = &tooltip_builder { + let mut active_tooltip = active_tooltip.lock(); + if is_hovered && active_tooltip.is_none() { + *active_tooltip = Some(tooltip_builder(view_state, cx)); + } else if !is_hovered { + active_tooltip.take(); + } + } + hover_listener(view_state, is_hovered, cx); } }); } + if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() { + if *element_state.hover_state.lock() { + cx.active_tooltip = Some(active_tooltip.clone()); + } + } + let active_state = element_state.active_state.clone(); if active_state.lock().is_none() { let active_group_bounds = stateful @@ -804,6 +823,7 @@ pub struct InteractiveElementState { hover_state: Arc>, pending_mouse_down: Arc>>, scroll_offset: Option>>>, + active_tooltip: Arc>>, } impl InteractiveElementState { @@ -1155,7 +1175,7 @@ pub(crate) type DragListener = pub(crate) type HoverListener = Box) + 'static>; -pub(crate) type TooltipBuilder = Box) -> AnyView + 'static>; +pub(crate) type TooltipBuilder = Arc) -> AnyView + 'static>; pub type KeyListener = Box< dyn Fn( diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index e998766bbb8126ac62b99ac2611caec72a941dc6..46ac30592bb8e6e60c134c702acb675e7fea4a39 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -987,6 +987,14 @@ impl<'a> WindowContext<'a> { cx.active_drag = Some(active_drag); }); }); + } else if let Some(active_tooltip) = self.app.active_tooltip.take() { + self.stack(1, |cx| { + cx.with_element_offset(Some(cx.mouse_position()), |cx| { + let available_space = + size(AvailableSpace::MinContent, AvailableSpace::MinContent); + active_tooltip.draw(available_space, cx); + }); + }); } self.window.root_view = Some(root_view); diff --git a/crates/ui2/src/components.rs b/crates/ui2/src/components.rs index 7a9cac01ca7c54999210b3220986062906196e1b..f10f8cee8d74cba0bdc0bfc6e307f147f8e424bc 100644 --- a/crates/ui2/src/components.rs +++ b/crates/ui2/src/components.rs @@ -31,6 +31,7 @@ mod theme_selector; mod title_bar; mod toast; mod toolbar; +mod tooltip; mod traffic_lights; mod workspace; @@ -67,5 +68,6 @@ pub use theme_selector::*; pub use title_bar::*; pub use toast::*; pub use toolbar::*; +pub use tooltip::*; pub use traffic_lights::*; pub use workspace::*; diff --git a/crates/ui2/src/components/tooltip.rs b/crates/ui2/src/components/tooltip.rs new file mode 100644 index 0000000000000000000000000000000000000000..eb53b506ebd8467eb9f6d31dab2abe36dd62496a --- /dev/null +++ b/crates/ui2/src/components/tooltip.rs @@ -0,0 +1,36 @@ +use gpui2::{ + div, px, Div, ParentElement, Render, SharedString, Styled, View, ViewContext, VisualContext, +}; +use theme2::ActiveTheme; + +#[derive(Clone, Debug)] +pub struct TextTooltip { + title: SharedString, +} + +impl TextTooltip { + pub fn new(str: SharedString) -> Self { + Self { title: str } + } + + pub fn build_view(str: SharedString, cx: &mut C) -> C::Result> { + cx.build_view(|cx| TextTooltip::new(str)) + } +} + +impl Render for TextTooltip { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + let theme = cx.theme(); + div() + .bg(theme.colors().background) + .rounded(px(8.)) + .border() + .border_color(theme.colors().border) + .text_color(theme.colors().text) + .pl_2() + .pr_2() + .child(self.title.clone()) + } +} diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index acda04c5a47cbf147ef1fac3d54c900be7eb5614..a1ec16848840355748666fb7cd0ad99ee789d4f9 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -9,9 +9,8 @@ use crate::{ use anyhow::Result; use collections::{HashMap, HashSet, VecDeque}; use gpui::{ - AppContext, AsyncWindowContext, Component, CursorStyle, Div, EntityId, EventEmitter, - FocusHandle, Model, PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, - WindowContext, + AnyView, AppContext, AsyncWindowContext, Component, Div, EntityId, EventEmitter, FocusHandle, + Model, PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, WindowContext, }; use parking_lot::Mutex; use project2::{Project, ProjectEntryId, ProjectPath}; @@ -27,7 +26,7 @@ use std::{ }, }; use ui::v_stack; -use ui::{prelude::*, Icon, IconButton, IconColor, IconElement}; +use ui::{prelude::*, Icon, IconButton, IconColor, IconElement, TextTooltip}; use util::truncate_and_remove_front; #[derive(PartialEq, Clone, Copy, Deserialize, Debug)] @@ -1402,7 +1401,10 @@ impl Pane { .on_hover(|_, hovered, _| { dbg!(hovered); }) - // .tooltip(|pane, cx| cx.create_view( tooltip.child("Hovering the tab")) + .when_some(item.tab_tooltip_text(cx), |div, text| { + div.tooltip(move |_, cx| TextTooltip::build_view(text.clone(), cx)) + }) + // .tooltip(|pane, cx| cx.build_view(|cx| div().child(title))) // .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx)) // .drag_over::(|d| d.bg(cx.theme().colors().element_drop_target)) // .on_drop(|_view, state: View, cx| { From f97046b86fae67d9cbf8ccf4e7b86781f9d2f7a9 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 3 Nov 2023 14:15:32 -0600 Subject: [PATCH 11/32] MOAR TOOLTIPS --- crates/gpui2/src/interactive.rs | 51 ++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index def7315a7cca6fe8cd3c7b9376438218cb226852..4a6185f7370239ef7c62d241df1d35e7aa7061b3 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -17,6 +17,7 @@ use std::{ ops::Deref, path::PathBuf, sync::Arc, + time::{Duration, Instant}, }; const DRAG_THRESHOLD: f64 = 2.; @@ -603,9 +604,6 @@ pub trait ElementInteraction: 'static { let was_hovered = element_state.hover_state.clone(); let has_mouse_down = element_state.pending_mouse_down.lock().is_some(); - let active_tooltip = element_state.active_tooltip.clone(); - let tooltip_builder = stateful.tooltip_builder.clone(); - cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; @@ -616,23 +614,39 @@ pub trait ElementInteraction: 'static { if is_hovered != was_hovered.clone() { *was_hovered = is_hovered; drop(was_hovered); - if let Some(tooltip_builder) = &tooltip_builder { - let mut active_tooltip = active_tooltip.lock(); - if is_hovered && active_tooltip.is_none() { - *active_tooltip = Some(tooltip_builder(view_state, cx)); - } else if !is_hovered { - active_tooltip.take(); - } - } hover_listener(view_state, is_hovered, cx); } }); } - if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() { - if *element_state.hover_state.lock() { - cx.active_tooltip = Some(active_tooltip.clone()); + // if we're hovered: + // if no timer, start timer + // if timer hits 1s, call tooltip_builder() + // + + if let Some(tooltip_builder) = &stateful.tooltip_builder { + let mut active_tooltip = element_state.active_tooltip.lock(); + let is_hovered = bounds.contains_point(&cx.mouse_position()) + && !element_state.pending_mouse_down.lock().is_some(); + + if is_hovered { + if let Some(active_tooltip) = active_tooltip { + active_tooltip.view = Some(tooltip_builder(cx)) + } else { + *active_tooltip = Some(ActiveTooltip { + hover_start: Instant::now(), + view: None, + }); + } + } else { + active_tooltip.take(); + } + + if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() { + if *element_state.hover_state.lock() { + cx.active_tooltip = Some(active_tooltip.clone()); + } } } @@ -823,7 +837,12 @@ pub struct InteractiveElementState { hover_state: Arc>, pending_mouse_down: Arc>>, scroll_offset: Option>>>, - active_tooltip: Arc>>, + active_tooltip: Arc>>, +} + +pub struct ActiveTooltip { + hover_start: Instant, + view: Option, } impl InteractiveElementState { @@ -1175,7 +1194,7 @@ pub(crate) type DragListener = pub(crate) type HoverListener = Box) + 'static>; -pub(crate) type TooltipBuilder = Arc) -> AnyView + 'static>; +pub(crate) type TooltipBuilder = Arc) -> AnyView + 'static>; pub type KeyListener = Box< dyn Fn( From 1361b617082bf730dfbd4aaa57bf8bbe4226e08f Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 3 Nov 2023 16:36:02 -0400 Subject: [PATCH 12/32] Use an `IconButton` for the tab close button --- crates/ui2/src/elements/icon.rs | 10 ---------- crates/workspace2/src/pane.rs | 19 ++++++++----------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/crates/ui2/src/elements/icon.rs b/crates/ui2/src/elements/icon.rs index 94e15ca0f1187dcc8851619fa7d94f0b295300c8..9c056d68d1ce4beab415c9ca7f8465ea9302f045 100644 --- a/crates/ui2/src/elements/icon.rs +++ b/crates/ui2/src/elements/icon.rs @@ -159,7 +159,6 @@ impl Icon { pub struct IconElement { icon: Icon, color: IconColor, - hover_color: Option, size: IconSize, } @@ -168,7 +167,6 @@ impl IconElement { Self { icon, color: IconColor::default(), - hover_color: None, size: IconSize::default(), } } @@ -178,11 +176,6 @@ impl IconElement { self } - pub fn hover_color(mut self, hover_color: impl Into>) -> Self { - self.hover_color = hover_color.into(); - self - } - pub fn size(mut self, size: IconSize) -> Self { self.size = size; self @@ -199,9 +192,6 @@ impl IconElement { .flex_none() .path(self.icon.path()) .text_color(self.color.color(cx)) - .when_some(self.hover_color, |this, hover_color| { - this.hover(|style| style.text_color(hover_color.color(cx))) - }) } } diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index a1ec16848840355748666fb7cd0ad99ee789d4f9..0c2ee5f46e9ef58667cd6c7cbb916638df9789ef 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -9,8 +9,8 @@ use crate::{ use anyhow::Result; use collections::{HashMap, HashSet, VecDeque}; use gpui::{ - AnyView, AppContext, AsyncWindowContext, Component, Div, EntityId, EventEmitter, FocusHandle, - Model, PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, WindowContext, + AppContext, AsyncWindowContext, Component, Div, EntityId, EventEmitter, FocusHandle, Model, + PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, WindowContext, }; use parking_lot::Mutex; use project2::{Project, ProjectEntryId, ProjectPath}; @@ -1366,15 +1366,12 @@ impl Pane { .id(item.id()) .invisible() .group_hover("", |style| style.visible()) - .child( - IconElement::new(Icon::Close) - .color(IconColor::Muted) - .hover_color(IconColor::Accent), - ) - .on_click(move |pane: &mut Self, _, cx| { - pane.close_item_by_id(id, SaveIntent::Close, cx) - .detach_and_log_err(cx); - }) + .child(IconButton::::new("close_tab", Icon::Close).on_click( + move |pane: &mut Self, cx| { + pane.close_item_by_id(id, SaveIntent::Close, cx) + .detach_and_log_err(cx); + }, + )) }; let (text_color, tab_bg, tab_hover_bg, tab_active_bg) = match ix == self.active_item_index { From b5224bdafd5417619f5652458bcc0b38d896c0d5 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 3 Nov 2023 16:40:46 -0400 Subject: [PATCH 13/32] Remove unneeded type qualification --- crates/workspace2/src/pane.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index 0c2ee5f46e9ef58667cd6c7cbb916638df9789ef..3cc9a8b5f2ee0c41d1b051fe4af83658128028e5 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -1366,7 +1366,7 @@ impl Pane { .id(item.id()) .invisible() .group_hover("", |style| style.visible()) - .child(IconButton::::new("close_tab", Icon::Close).on_click( + .child(IconButton::new("close_tab", Icon::Close).on_click( move |pane: &mut Self, cx| { pane.close_item_by_id(id, SaveIntent::Close, cx) .detach_and_log_err(cx); From 3834e26f7150215502754eae999f7fc35ca11008 Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 3 Nov 2023 18:02:58 -0400 Subject: [PATCH 14/32] Tooltips in mouse event handler & fix executor timer Co-Authored-By: Conrad Irwin --- crates/gpui2/build.rs | 1 + crates/gpui2/src/interactive.rs | 56 +++++++++------------ crates/gpui2/src/platform/mac/dispatcher.rs | 14 +----- crates/gpui2/src/window.rs | 13 +++-- crates/ui2/src/components/tooltip.rs | 34 +++++++++++-- crates/workspace2/src/pane.rs | 8 +-- 6 files changed, 67 insertions(+), 59 deletions(-) diff --git a/crates/gpui2/build.rs b/crates/gpui2/build.rs index c9abfaa6bb5e79ad07d77b1855c9414c2b0b5b05..6e8a0868b969c7a85627fd974f0f1bde793eb587 100644 --- a/crates/gpui2/build.rs +++ b/crates/gpui2/build.rs @@ -20,6 +20,7 @@ fn generate_dispatch_bindings() { .header("src/platform/mac/dispatch.h") .allowlist_var("_dispatch_main_q") .allowlist_var("DISPATCH_QUEUE_PRIORITY_DEFAULT") + .allowlist_var("DISPATCH_TIME_NOW") .allowlist_function("dispatch_get_global_queue") .allowlist_function("dispatch_async_f") .allowlist_function("dispatch_after_f") diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index 4a6185f7370239ef7c62d241df1d35e7aa7061b3..f7a8f033c4be2c8683587481385b07ecd60800ad 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -17,7 +17,6 @@ use std::{ ops::Deref, path::PathBuf, sync::Arc, - time::{Duration, Instant}, }; const DRAG_THRESHOLD: f64 = 2.; @@ -602,13 +601,14 @@ pub trait ElementInteraction: 'static { if let Some(hover_listener) = stateful.hover_listener.take() { let was_hovered = element_state.hover_state.clone(); - let has_mouse_down = element_state.pending_mouse_down.lock().is_some(); + let has_mouse_down = element_state.pending_mouse_down.clone(); cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } - let is_hovered = bounds.contains_point(&event.position) && !has_mouse_down; + let is_hovered = + bounds.contains_point(&event.position) && has_mouse_down.lock().is_none(); let mut was_hovered = was_hovered.lock(); if is_hovered != was_hovered.clone() { @@ -620,33 +620,30 @@ pub trait ElementInteraction: 'static { }); } - // if we're hovered: - // if no timer, start timer - // if timer hits 1s, call tooltip_builder() - // + if let Some(tooltip_builder) = stateful.tooltip_builder.take() { + let tooltip_view = element_state.tooltip_view.clone(); + let pending_mouse_down = element_state.pending_mouse_down.clone(); - if let Some(tooltip_builder) = &stateful.tooltip_builder { - let mut active_tooltip = element_state.active_tooltip.lock(); - let is_hovered = bounds.contains_point(&cx.mouse_position()) - && !element_state.pending_mouse_down.lock().is_some(); + cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| { + if phase != DispatchPhase::Bubble { + return; + } + + let is_hovered = bounds.contains_point(&event.position) + && pending_mouse_down.lock().is_none(); + let mut tooltip_view = tooltip_view.lock(); - if is_hovered { - if let Some(active_tooltip) = active_tooltip { - active_tooltip.view = Some(tooltip_builder(cx)) + if is_hovered { + if tooltip_view.is_none() { + *tooltip_view = Some(tooltip_builder(view_state, cx)); + } } else { - *active_tooltip = Some(ActiveTooltip { - hover_start: Instant::now(), - view: None, - }); + tooltip_view.take(); } - } else { - active_tooltip.take(); - } + }); - if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() { - if *element_state.hover_state.lock() { - cx.active_tooltip = Some(active_tooltip.clone()); - } + if let Some(active_tooltip) = element_state.tooltip_view.lock().as_ref() { + cx.active_tooltip = Some(active_tooltip.clone()); } } @@ -837,12 +834,7 @@ pub struct InteractiveElementState { hover_state: Arc>, pending_mouse_down: Arc>>, scroll_offset: Option>>>, - active_tooltip: Arc>>, -} - -pub struct ActiveTooltip { - hover_start: Instant, - view: Option, + tooltip_view: Arc>>, } impl InteractiveElementState { @@ -1194,7 +1186,7 @@ pub(crate) type DragListener = pub(crate) type HoverListener = Box) + 'static>; -pub(crate) type TooltipBuilder = Arc) -> AnyView + 'static>; +pub(crate) type TooltipBuilder = Arc) -> AnyView + 'static>; pub type KeyListener = Box< dyn Fn( diff --git a/crates/gpui2/src/platform/mac/dispatcher.rs b/crates/gpui2/src/platform/mac/dispatcher.rs index f5334912c6b7aec93fed2af3c33832ff241313c9..68c0e3b4f53c4040899ac0d344dc1dec095a9bc1 100644 --- a/crates/gpui2/src/platform/mac/dispatcher.rs +++ b/crates/gpui2/src/platform/mac/dispatcher.rs @@ -11,11 +11,7 @@ use objc::{ }; use parking::{Parker, Unparker}; use parking_lot::Mutex; -use std::{ - ffi::c_void, - sync::Arc, - time::{Duration, SystemTime}, -}; +use std::{ffi::c_void, sync::Arc, time::Duration}; include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs")); @@ -62,16 +58,10 @@ impl PlatformDispatcher for MacDispatcher { } fn dispatch_after(&self, duration: Duration, runnable: Runnable) { - let now = SystemTime::now(); - let after_duration = now - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap() - .as_nanos() as u64 - + duration.as_nanos() as u64; unsafe { let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0); - let when = dispatch_time(0, after_duration as i64); + let when = dispatch_time(DISPATCH_TIME_NOW as u64, duration.as_nanos() as i64); dispatch_after_f( when, queue, diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 46ac30592bb8e6e60c134c702acb675e7fea4a39..fe6f516e434b4bc186467adf0d19e3e33a8a3d2d 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -989,11 +989,14 @@ impl<'a> WindowContext<'a> { }); } else if let Some(active_tooltip) = self.app.active_tooltip.take() { self.stack(1, |cx| { - cx.with_element_offset(Some(cx.mouse_position()), |cx| { - let available_space = - size(AvailableSpace::MinContent, AvailableSpace::MinContent); - active_tooltip.draw(available_space, cx); - }); + cx.with_element_offset( + Some(cx.mouse_position() + Point::new(px(8.0), px(8.0))), + |cx| { + let available_space = + size(AvailableSpace::MinContent, AvailableSpace::MinContent); + active_tooltip.draw(available_space, cx); + }, + ); }); } diff --git a/crates/ui2/src/components/tooltip.rs b/crates/ui2/src/components/tooltip.rs index eb53b506ebd8467eb9f6d31dab2abe36dd62496a..f94518224dae49df85dfc69d8830be609c0b21c0 100644 --- a/crates/ui2/src/components/tooltip.rs +++ b/crates/ui2/src/components/tooltip.rs @@ -1,20 +1,44 @@ +use std::time::Duration; + use gpui2::{ - div, px, Div, ParentElement, Render, SharedString, Styled, View, ViewContext, VisualContext, + div, px, Component, Div, ParentElement, Render, SharedString, Styled, View, ViewContext, + VisualContext, WindowContext, }; use theme2::ActiveTheme; +const DELAY: Duration = Duration::from_millis(500); + #[derive(Clone, Debug)] pub struct TextTooltip { title: SharedString, + visible: bool, } impl TextTooltip { pub fn new(str: SharedString) -> Self { - Self { title: str } + Self { + title: str, + visible: false, + } } - pub fn build_view(str: SharedString, cx: &mut C) -> C::Result> { - cx.build_view(|cx| TextTooltip::new(str)) + pub fn build_view(str: SharedString, cx: &mut WindowContext) -> View { + let view = cx.build_view(|cx| TextTooltip::new(str)); + + let handle = view.downgrade(); + cx.spawn(|mut cx| async move { + cx.background_executor().timer(DELAY).await; + + handle + .update(&mut cx, |this, cx| { + this.visible = true; + cx.notify(); + }) + .ok(); + }) + .detach(); + + view } } @@ -24,9 +48,11 @@ impl Render for TextTooltip { fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let theme = cx.theme(); div() + .when(!self.visible, |this| this.invisible()) .bg(theme.colors().background) .rounded(px(8.)) .border() + .font("Zed Sans") .border_color(theme.colors().border) .text_color(theme.colors().text) .pl_2() diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index a1ec16848840355748666fb7cd0ad99ee789d4f9..64b995b538a8773a0cac848cc03b7c9e1f58cffb 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -9,8 +9,8 @@ use crate::{ use anyhow::Result; use collections::{HashMap, HashSet, VecDeque}; use gpui::{ - AnyView, AppContext, AsyncWindowContext, Component, Div, EntityId, EventEmitter, FocusHandle, - Model, PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, WindowContext, + AppContext, AsyncWindowContext, Component, Div, EntityId, EventEmitter, FocusHandle, Model, + PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, WindowContext, }; use parking_lot::Mutex; use project2::{Project, ProjectEntryId, ProjectPath}; @@ -1398,13 +1398,9 @@ impl Pane { .group("") .id(item.id()) .cursor_pointer() - .on_hover(|_, hovered, _| { - dbg!(hovered); - }) .when_some(item.tab_tooltip_text(cx), |div, text| { div.tooltip(move |_, cx| TextTooltip::build_view(text.clone(), cx)) }) - // .tooltip(|pane, cx| cx.build_view(|cx| div().child(title))) // .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx)) // .drag_over::(|d| d.bg(cx.theme().colors().element_drop_target)) // .on_drop(|_view, state: View, cx| { From 4725cd2cd6b396c5adf19c0a27d87a1750598cf3 Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 3 Nov 2023 18:37:15 -0400 Subject: [PATCH 15/32] Move more tooltip logic into gpui2 & fix tooltip moving on paint Co-Authored-By: Conrad Irwin --- crates/gpui2/src/app.rs | 7 +++- crates/gpui2/src/geometry.rs | 2 +- crates/gpui2/src/interactive.rs | 58 ++++++++++++++++++++++------ crates/gpui2/src/window.rs | 13 +++---- crates/ui2/src/components/tooltip.rs | 33 +--------------- crates/workspace2/src/pane.rs | 2 +- 6 files changed, 61 insertions(+), 54 deletions(-) diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 974395e8971f92a3524a5a8177f792a567b88904..9e454dc6529fae93fc799d23f5ff43c52e3ed834 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -157,7 +157,7 @@ pub struct AppContext { flushing_effects: bool, pending_updates: usize, pub(crate) active_drag: Option, - pub(crate) active_tooltip: Option, + pub(crate) active_tooltip: Option, pub(crate) next_frame_callbacks: HashMap>, pub(crate) frame_consumers: HashMap>, pub(crate) background_executor: BackgroundExecutor, @@ -898,3 +898,8 @@ pub(crate) struct AnyDrag { pub view: AnyView, pub cursor_offset: Point, } + +pub(crate) struct AnyTooltip { + pub view: AnyView, + pub cursor_offset: Point, +} diff --git a/crates/gpui2/src/geometry.rs b/crates/gpui2/src/geometry.rs index 081b11aae0e250237e091bf8ab7ecc565e57c960..d6755a53973f00d5fee4fd11912f6e73da26cf71 100644 --- a/crates/gpui2/src/geometry.rs +++ b/crates/gpui2/src/geometry.rs @@ -21,7 +21,7 @@ pub fn point(x: T, y: T) -> Point { } impl Point { - pub fn new(x: T, y: T) -> Self { + pub const fn new(x: T, y: T) -> Self { Self { x, y } } diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index f7a8f033c4be2c8683587481385b07ecd60800ad..dd09ad512bf25d2e3049efa63ea032256df35d7e 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -1,8 +1,8 @@ use crate::{ - div, point, px, Action, AnyDrag, AnyView, AppContext, BorrowWindow, Bounds, Component, - DispatchContext, DispatchPhase, Div, Element, ElementId, FocusHandle, KeyMatch, Keystroke, - Modifiers, Overflow, Pixels, Point, Render, SharedString, Size, Style, StyleRefinement, View, - ViewContext, + div, point, px, Action, AnyDrag, AnyTooltip, AnyView, AppContext, BorrowWindow, Bounds, + Component, DispatchContext, DispatchPhase, Div, Element, ElementId, FocusHandle, KeyMatch, + Keystroke, Modifiers, Overflow, Pixels, Point, Render, SharedString, Size, Style, + StyleRefinement, View, ViewContext, }; use collections::HashMap; use derive_more::{Deref, DerefMut}; @@ -17,9 +17,12 @@ use std::{ ops::Deref, path::PathBuf, sync::Arc, + time::Duration, }; const DRAG_THRESHOLD: f64 = 2.; +const TOOLTIP_DELAY: Duration = Duration::from_millis(500); +const TOOLTIP_OFFSET: Point = Point::new(px(10.0), px(8.0)); pub trait StatelessInteractive: Element { fn stateless_interaction(&mut self) -> &mut StatelessInteraction; @@ -621,7 +624,7 @@ pub trait ElementInteraction: 'static { } if let Some(tooltip_builder) = stateful.tooltip_builder.take() { - let tooltip_view = element_state.tooltip_view.clone(); + let active_tooltip = element_state.active_tooltip.clone(); let pending_mouse_down = element_state.pending_mouse_down.clone(); cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| { @@ -631,19 +634,44 @@ pub trait ElementInteraction: 'static { let is_hovered = bounds.contains_point(&event.position) && pending_mouse_down.lock().is_none(); - let mut tooltip_view = tooltip_view.lock(); + let mut tooltip_lock = active_tooltip.lock(); if is_hovered { - if tooltip_view.is_none() { - *tooltip_view = Some(tooltip_builder(view_state, cx)); + if tooltip_lock.is_none() { + *tooltip_lock = Some(ActiveTooltip { + view: tooltip_builder(view_state, cx), + visible: false, + coordinates: event.position, + }); + + let active_tooltip = active_tooltip.clone(); + cx.spawn(move |view, mut cx| async move { + cx.background_executor().timer(TOOLTIP_DELAY).await; + + view.update(&mut cx, |_, cx| { + if let Some(active_tooltip) = active_tooltip.lock().as_mut() { + active_tooltip.visible = true; + active_tooltip.coordinates = + cx.mouse_position() + TOOLTIP_OFFSET; + } + cx.notify(); + }) + .ok() + }) + .detach(); } } else { - tooltip_view.take(); + tooltip_lock.take(); } }); - if let Some(active_tooltip) = element_state.tooltip_view.lock().as_ref() { - cx.active_tooltip = Some(active_tooltip.clone()); + if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() { + if active_tooltip.visible { + cx.active_tooltip = Some(AnyTooltip { + view: active_tooltip.view.clone(), + cursor_offset: active_tooltip.coordinates, + }); + } } } @@ -834,7 +862,13 @@ pub struct InteractiveElementState { hover_state: Arc>, pending_mouse_down: Arc>>, scroll_offset: Option>>>, - tooltip_view: Arc>>, + active_tooltip: Arc>>, +} + +struct ActiveTooltip { + view: AnyView, + visible: bool, + coordinates: Point, } impl InteractiveElementState { diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index fe6f516e434b4bc186467adf0d19e3e33a8a3d2d..9cab40082b02912eced41363a2afa6506fb3d9c0 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -989,14 +989,11 @@ impl<'a> WindowContext<'a> { }); } else if let Some(active_tooltip) = self.app.active_tooltip.take() { self.stack(1, |cx| { - cx.with_element_offset( - Some(cx.mouse_position() + Point::new(px(8.0), px(8.0))), - |cx| { - let available_space = - size(AvailableSpace::MinContent, AvailableSpace::MinContent); - active_tooltip.draw(available_space, cx); - }, - ); + cx.with_element_offset(Some(active_tooltip.cursor_offset), |cx| { + let available_space = + size(AvailableSpace::MinContent, AvailableSpace::MinContent); + active_tooltip.view.draw(available_space, cx); + }); }); } diff --git a/crates/ui2/src/components/tooltip.rs b/crates/ui2/src/components/tooltip.rs index f94518224dae49df85dfc69d8830be609c0b21c0..0bc00a9be1120e80c2b840bc064ddf3ee584a1c0 100644 --- a/crates/ui2/src/components/tooltip.rs +++ b/crates/ui2/src/components/tooltip.rs @@ -1,44 +1,16 @@ use std::time::Duration; -use gpui2::{ - div, px, Component, Div, ParentElement, Render, SharedString, Styled, View, ViewContext, - VisualContext, WindowContext, -}; +use gpui2::{div, px, Div, ParentElement, Render, SharedString, Styled, ViewContext}; use theme2::ActiveTheme; -const DELAY: Duration = Duration::from_millis(500); - #[derive(Clone, Debug)] pub struct TextTooltip { title: SharedString, - visible: bool, } impl TextTooltip { pub fn new(str: SharedString) -> Self { - Self { - title: str, - visible: false, - } - } - - pub fn build_view(str: SharedString, cx: &mut WindowContext) -> View { - let view = cx.build_view(|cx| TextTooltip::new(str)); - - let handle = view.downgrade(); - cx.spawn(|mut cx| async move { - cx.background_executor().timer(DELAY).await; - - handle - .update(&mut cx, |this, cx| { - this.visible = true; - cx.notify(); - }) - .ok(); - }) - .detach(); - - view + Self { title: str } } } @@ -48,7 +20,6 @@ impl Render for TextTooltip { fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let theme = cx.theme(); div() - .when(!self.visible, |this| this.invisible()) .bg(theme.colors().background) .rounded(px(8.)) .border() diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index 64b995b538a8773a0cac848cc03b7c9e1f58cffb..131a3e977b4cd8a2e461f225e26413e9fe4f50e4 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -1399,7 +1399,7 @@ impl Pane { .id(item.id()) .cursor_pointer() .when_some(item.tab_tooltip_text(cx), |div, text| { - div.tooltip(move |_, cx| TextTooltip::build_view(text.clone(), cx)) + div.tooltip(move |_, cx| cx.build_view(|cx| TextTooltip::new(text.clone()))) }) // .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx)) // .drag_over::(|d| d.bg(cx.theme().colors().element_drop_target)) From de5458cfe0f419324a7258647b887c0eb8db5c71 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 3 Nov 2023 21:40:28 -0600 Subject: [PATCH 16/32] Update tooltip code a bit This fixes a tiny UX bug where the tooltip would appear to move if you hovered over an element, then moved your mouse out and back within 500ms. The fix is to retain the task, so we can drop it to cancel it when the mouse leaves. Also changes the time we construct the tooltip to the time it first shows. --- crates/gpui2/src/app.rs | 1 + crates/gpui2/src/interactive.rs | 64 ++++++++++++++-------------- crates/ui2/src/components/tooltip.rs | 2 - 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 9e454dc6529fae93fc799d23f5ff43c52e3ed834..bc9101fa0cc18b6a826e45b1230bfc31d3223578 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -899,6 +899,7 @@ pub(crate) struct AnyDrag { pub cursor_offset: Point, } +#[derive(Clone)] pub(crate) struct AnyTooltip { pub view: AnyView, pub cursor_offset: Point, diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index dd09ad512bf25d2e3049efa63ea032256df35d7e..da208b38131f8ddd0e297c47bc504065af232d15 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -2,7 +2,7 @@ use crate::{ div, point, px, Action, AnyDrag, AnyTooltip, AnyView, AppContext, BorrowWindow, Bounds, Component, DispatchContext, DispatchPhase, Div, Element, ElementId, FocusHandle, KeyMatch, Keystroke, Modifiers, Overflow, Pixels, Point, Render, SharedString, Size, Style, - StyleRefinement, View, ViewContext, + StyleRefinement, Task, View, ViewContext, }; use collections::HashMap; use derive_more::{Deref, DerefMut}; @@ -627,50 +627,48 @@ pub trait ElementInteraction: 'static { let active_tooltip = element_state.active_tooltip.clone(); let pending_mouse_down = element_state.pending_mouse_down.clone(); - cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| { + cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } let is_hovered = bounds.contains_point(&event.position) && pending_mouse_down.lock().is_none(); - let mut tooltip_lock = active_tooltip.lock(); - - if is_hovered { - if tooltip_lock.is_none() { - *tooltip_lock = Some(ActiveTooltip { - view: tooltip_builder(view_state, cx), - visible: false, - coordinates: event.position, - }); + if !is_hovered { + active_tooltip.lock().take(); + return; + } + if active_tooltip.lock().is_none() { + let task = cx.spawn({ let active_tooltip = active_tooltip.clone(); - cx.spawn(move |view, mut cx| async move { - cx.background_executor().timer(TOOLTIP_DELAY).await; + let tooltip_builder = tooltip_builder.clone(); - view.update(&mut cx, |_, cx| { - if let Some(active_tooltip) = active_tooltip.lock().as_mut() { - active_tooltip.visible = true; - active_tooltip.coordinates = - cx.mouse_position() + TOOLTIP_OFFSET; - } + move |view, mut cx| async move { + cx.background_executor().timer(TOOLTIP_DELAY).await; + view.update(&mut cx, move |view_state, cx| { + active_tooltip.lock().replace(ActiveTooltip { + waiting: None, + tooltip: Some(AnyTooltip { + view: tooltip_builder(view_state, cx), + cursor_offset: cx.mouse_position() + TOOLTIP_OFFSET, + }), + }); cx.notify(); }) - .ok() - }) - .detach(); - } - } else { - tooltip_lock.take(); + .ok(); + } + }); + active_tooltip.lock().replace(ActiveTooltip { + waiting: Some(task), + tooltip: None, + }); } }); if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() { - if active_tooltip.visible { - cx.active_tooltip = Some(AnyTooltip { - view: active_tooltip.view.clone(), - cursor_offset: active_tooltip.coordinates, - }); + if active_tooltip.tooltip.is_some() { + cx.active_tooltip = active_tooltip.tooltip.clone() } } } @@ -866,9 +864,9 @@ pub struct InteractiveElementState { } struct ActiveTooltip { - view: AnyView, - visible: bool, - coordinates: Point, + #[allow(unused)] // used to drop the task + waiting: Option>, + tooltip: Option, } impl InteractiveElementState { diff --git a/crates/ui2/src/components/tooltip.rs b/crates/ui2/src/components/tooltip.rs index 0bc00a9be1120e80c2b840bc064ddf3ee584a1c0..c05214eea4e8d977ab85d875b341e1165a785b3a 100644 --- a/crates/ui2/src/components/tooltip.rs +++ b/crates/ui2/src/components/tooltip.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - use gpui2::{div, px, Div, ParentElement, Render, SharedString, Styled, ViewContext}; use theme2::ActiveTheme; From 9f40a5c53f29e6a5c2902cab4a62af3d9154d2d9 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 4 Nov 2023 13:54:34 +0200 Subject: [PATCH 17/32] Suppress unused vars warning generated by gpui macro --- crates/gpui_macros/src/gpui_macros.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/gpui_macros/src/gpui_macros.rs b/crates/gpui_macros/src/gpui_macros.rs index aa55c27eaad9069fd8964ea2f2b4f64195bd458c..62fba3b61237bb0cc31b28211f2680d105b559d1 100644 --- a/crates/gpui_macros/src/gpui_macros.rs +++ b/crates/gpui_macros/src/gpui_macros.rs @@ -170,6 +170,8 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { #max_retries, #detect_nondeterminism, &mut |cx, foreground_platform, deterministic, seed| { + // some of the macro contents do not use all variables, silence the warnings + let _ = (&cx, &foreground_platform, &deterministic, &seed); #cx_vars cx.foreground().run(#inner_fn_name(#inner_fn_args)); #cx_teardowns @@ -247,6 +249,8 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { #max_retries, #detect_nondeterminism, &mut |cx, foreground_platform, deterministic, seed| { + // some of the macro contents do not use all variables, silence the warnings + let _ = (&cx, &foreground_platform, &deterministic, &seed); #cx_vars #inner_fn_name(#inner_fn_args); #cx_teardowns From b125cc279f5cbcb2042d7383322119fcddc2e00c Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Sat, 4 Nov 2023 11:24:31 -0400 Subject: [PATCH 18/32] Simplify toggle, do some reorganization --- crates/ui2/src/components.rs | 4 + crates/ui2/src/components/button.rs | 21 +- crates/ui2/src/components/context_menu.rs | 17 +- crates/ui2/src/components/list.rs | 324 +++--------------- crates/ui2/src/components/player.rs | 18 + crates/ui2/src/components/slot.rs | 14 + crates/ui2/src/components/toggle.rs | 61 ++++ crates/ui2/src/prelude.rs | 76 ---- crates/ui2/src/static_data.rs | 125 ++----- crates/ui2/src/to_extract/collab_panel.rs | 21 +- .../ui2/src/to_extract/notifications_panel.rs | 29 +- crates/ui2/src/to_extract/project_panel.rs | 13 +- 12 files changed, 224 insertions(+), 499 deletions(-) create mode 100644 crates/ui2/src/components/slot.rs create mode 100644 crates/ui2/src/components/toggle.rs diff --git a/crates/ui2/src/components.rs b/crates/ui2/src/components.rs index f7674c2bd4db5aa4a79ca9d0cc2ed6597ab36002..692cd55e8ec065831c2e85d8a564e90713c3c798 100644 --- a/crates/ui2/src/components.rs +++ b/crates/ui2/src/components.rs @@ -16,9 +16,11 @@ mod palette; mod panel; mod player; mod player_stack; +mod slot; mod stack; mod tab; mod toast; +mod toggle; mod tool_divider; pub use avatar::*; @@ -39,7 +41,9 @@ pub use palette::*; pub use panel::*; pub use player::*; pub use player_stack::*; +pub use slot::*; pub use stack::*; pub use tab::*; pub use toast::*; +pub use toggle::*; pub use tool_divider::*; diff --git a/crates/ui2/src/components/button.rs b/crates/ui2/src/components/button.rs index 073bcdbb4589ed9fc87e4b63dd6acd0bfd3176f4..381db20a8336ccf02694537f3760d5e10a23989a 100644 --- a/crates/ui2/src/components/button.rs +++ b/crates/ui2/src/components/button.rs @@ -2,8 +2,27 @@ use std::sync::Arc; use gpui2::{div, rems, DefiniteLength, Hsla, MouseButton, WindowContext}; -use crate::prelude::*; use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor, LineHeightStyle}; +use crate::{prelude::*, IconButton}; + +/// Provides the flexibility to use either a standard +/// button or an icon button in a given context. +pub enum ButtonOrIconButton { + Button(Button), + IconButton(IconButton), +} + +impl From> for ButtonOrIconButton { + fn from(value: Button) -> Self { + Self::Button(value) + } +} + +impl From> for ButtonOrIconButton { + fn from(value: IconButton) -> Self { + Self::IconButton(value) + } +} #[derive(Default, PartialEq, Clone, Copy)] pub enum IconPosition { diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 8345be1b3577724f3967205c3f493abf5945bc2d..4f265a376dec5847e89be537064a843515607341 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -8,7 +8,7 @@ pub enum ContextMenuItem { } impl ContextMenuItem { - fn to_list_item(self) -> ListItem { + fn to_list_item(self) -> ListItem { match self { ContextMenuItem::Header(label) => ListSubHeader::new(label).into(), ContextMenuItem::Entry(label) => { @@ -49,15 +49,12 @@ impl ContextMenu { .bg(cx.theme().colors().elevated_surface) .border() .border_color(cx.theme().colors().border) - .child( - List::new( - self.items - .into_iter() - .map(ContextMenuItem::to_list_item) - .collect(), - ) - .toggle(ToggleState::Toggled), - ) + .child(List::new( + self.items + .into_iter() + .map(ContextMenuItem::to_list_item::) + .collect(), + )) } } diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index 50a86ff256b7a4e9e6f7992acd6f2178c8c32c6a..543432a8935a5392e96e5e1a8ca074adf5388d54 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -1,11 +1,11 @@ -use gpui2::{div, px, relative, Div}; +use gpui2::div; use crate::settings::user_settings; use crate::{ - h_stack, v_stack, Avatar, ClickHandler, Icon, IconColor, IconElement, IconSize, Label, - LabelColor, + disclosure_control, h_stack, v_stack, Avatar, Icon, IconColor, IconElement, IconSize, Label, + LabelColor, Toggle, }; -use crate::{prelude::*, Button}; +use crate::{prelude::*, GraphicSlot}; #[derive(Clone, Copy, Default, Debug, PartialEq)] pub enum ListItemVariant { @@ -29,7 +29,7 @@ pub struct ListHeader { left_icon: Option, meta: Option, variant: ListItemVariant, - toggleable: Toggleable, + toggle: Toggle, } impl ListHeader { @@ -39,17 +39,12 @@ impl ListHeader { left_icon: None, meta: None, variant: ListItemVariant::default(), - toggleable: Toggleable::NotToggleable, + toggle: Toggle::NotToggleable, } } - pub fn toggle(mut self, toggle: ToggleState) -> Self { - self.toggleable = toggle.into(); - self - } - - pub fn toggleable(mut self, toggleable: Toggleable) -> Self { - self.toggleable = toggleable; + pub fn toggle(mut self, toggle: Toggle) -> Self { + self.toggle = toggle; self } @@ -63,30 +58,8 @@ impl ListHeader { self } - fn disclosure_control(&self) -> Div { - let is_toggleable = self.toggleable != Toggleable::NotToggleable; - let is_toggled = Toggleable::is_toggled(&self.toggleable); - - match (is_toggleable, is_toggled) { - (false, _) => div(), - (_, true) => div().child( - IconElement::new(Icon::ChevronDown) - .color(IconColor::Muted) - .size(IconSize::Small), - ), - (_, false) => div().child( - IconElement::new(Icon::ChevronRight) - .color(IconColor::Muted) - .size(IconSize::Small), - ), - } - } - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let is_toggleable = self.toggleable != Toggleable::NotToggleable; - let is_toggled = self.toggleable.is_toggled(); - - let disclosure_control = self.disclosure_control(); + let disclosure_control = disclosure_control(self.toggle); let meta = match self.meta { Some(ListHeaderMeta::Tools(icons)) => div().child( @@ -193,12 +166,6 @@ impl ListSubHeader { } } -#[derive(Clone)] -pub enum LeftContent { - Icon(Icon), - Avatar(SharedString), -} - #[derive(Default, PartialEq, Copy, Clone)] pub enum ListEntrySize { #[default] @@ -207,44 +174,36 @@ pub enum ListEntrySize { } #[derive(Component)] -pub enum ListItem { +pub enum ListItem { Entry(ListEntry), - Details(ListDetailsEntry), Separator(ListSeparator), Header(ListSubHeader), } -impl From for ListItem { +impl From for ListItem { fn from(entry: ListEntry) -> Self { Self::Entry(entry) } } -impl From> for ListItem { - fn from(entry: ListDetailsEntry) -> Self { - Self::Details(entry) - } -} - -impl From for ListItem { +impl From for ListItem { fn from(entry: ListSeparator) -> Self { Self::Separator(entry) } } -impl From for ListItem { +impl From for ListItem { fn from(entry: ListSubHeader) -> Self { Self::Header(entry) } } -impl ListItem { - fn render(self, view: &mut V, cx: &mut ViewContext) -> impl Component { +impl ListItem { + fn render(self, view: &mut V, cx: &mut ViewContext) -> impl Component { match self { ListItem::Entry(entry) => div().child(entry.render(view, cx)), ListItem::Separator(separator) => div().child(separator.render(view, cx)), ListItem::Header(header) => div().child(header.render(view, cx)), - ListItem::Details(details) => div().child(details.render(view, cx)), } } @@ -263,31 +222,29 @@ impl ListItem { #[derive(Component)] pub struct ListEntry { - disclosure_control_style: DisclosureControlVisibility, + disabled: bool, + // TODO: Reintroduce this + // disclosure_control_style: DisclosureControlVisibility, indent_level: u32, label: Label, - left_content: Option, - variant: ListItemVariant, - size: ListEntrySize, - state: InteractionState, - toggle: Option, + left_slot: Option, overflow: OverflowStyle, + size: ListEntrySize, + toggle: Toggle, + variant: ListItemVariant, } impl ListEntry { pub fn new(label: Label) -> Self { Self { - disclosure_control_style: DisclosureControlVisibility::default(), + disabled: false, indent_level: 0, label, - variant: ListItemVariant::default(), - left_content: None, - size: ListEntrySize::default(), - state: InteractionState::default(), - // TODO: Should use Toggleable::NotToggleable - // or remove Toggleable::NotToggleable from the system - toggle: None, + left_slot: None, overflow: OverflowStyle::Hidden, + size: ListEntrySize::default(), + toggle: Toggle::NotToggleable, + variant: ListItemVariant::default(), } } @@ -301,28 +258,23 @@ impl ListEntry { self } - pub fn toggle(mut self, toggle: ToggleState) -> Self { - self.toggle = Some(toggle); + pub fn toggle(mut self, toggle: Toggle) -> Self { + self.toggle = toggle; self } - pub fn left_content(mut self, left_content: LeftContent) -> Self { - self.left_content = Some(left_content); + pub fn left_content(mut self, left_content: GraphicSlot) -> Self { + self.left_slot = Some(left_content); self } pub fn left_icon(mut self, left_icon: Icon) -> Self { - self.left_content = Some(LeftContent::Icon(left_icon)); + self.left_slot = Some(GraphicSlot::Icon(left_icon)); self } pub fn left_avatar(mut self, left_avatar: impl Into) -> Self { - self.left_content = Some(LeftContent::Avatar(left_avatar.into())); - self - } - - pub fn state(mut self, state: InteractionState) -> Self { - self.state = state; + self.left_slot = Some(GraphicSlot::Avatar(left_avatar.into())); self } @@ -331,63 +283,19 @@ impl ListEntry { self } - pub fn disclosure_control_style( - mut self, - disclosure_control_style: DisclosureControlVisibility, - ) -> Self { - self.disclosure_control_style = disclosure_control_style; - self - } - - fn label_color(&self) -> LabelColor { - match self.state { - InteractionState::Disabled => LabelColor::Disabled, - _ => Default::default(), - } - } - - fn icon_color(&self) -> IconColor { - match self.state { - InteractionState::Disabled => IconColor::Disabled, - _ => Default::default(), - } - } - - fn disclosure_control( - &mut self, - cx: &mut ViewContext, - ) -> Option> { - let disclosure_control_icon = if let Some(ToggleState::Toggled) = self.toggle { - IconElement::new(Icon::ChevronDown) - } else { - IconElement::new(Icon::ChevronRight) - } - .color(IconColor::Muted) - .size(IconSize::Small); - - match (self.toggle, self.disclosure_control_style) { - (Some(_), DisclosureControlVisibility::OnHover) => { - Some(div().absolute().neg_left_5().child(disclosure_control_icon)) - } - (Some(_), DisclosureControlVisibility::Always) => { - Some(div().child(disclosure_control_icon)) - } - (None, _) => None, - } - } - - fn render(mut self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { let settings = user_settings(cx); - let left_content = match self.left_content.clone() { - Some(LeftContent::Icon(i)) => Some( + let left_content = match self.left_slot.clone() { + Some(GraphicSlot::Icon(i)) => Some( h_stack().child( IconElement::new(i) .size(IconSize::Small) .color(IconColor::Muted), ), ), - Some(LeftContent::Avatar(src)) => Some(h_stack().child(Avatar::new(src))), + Some(GraphicSlot::Avatar(src)) => Some(h_stack().child(Avatar::new(src))), + Some(GraphicSlot::PublicActor(src)) => Some(h_stack().child(Avatar::new(src))), None => None, }; @@ -400,10 +308,7 @@ impl ListEntry { .relative() .group("") .bg(cx.theme().colors().surface) - .when(self.state == InteractionState::Focused, |this| { - this.border() - .border_color(cx.theme().colors().border_focused) - }) + // TODO: Add focus state .child( sized_item .when(self.variant == ListItemVariant::Inset, |this| this.px_2()) @@ -425,131 +330,13 @@ impl ListEntry { .gap_1() .items_center() .relative() - .children(self.disclosure_control(cx)) + .child(disclosure_control(self.toggle)) .children(left_content) .child(self.label), ) } } -struct ListDetailsEntryHandlers { - click: Option>, -} - -impl Default for ListDetailsEntryHandlers { - fn default() -> Self { - Self { click: None } - } -} - -#[derive(Component)] -pub struct ListDetailsEntry { - label: SharedString, - meta: Option, - left_content: Option, - handlers: ListDetailsEntryHandlers, - actions: Option>>, - // TODO: make this more generic instead of - // specifically for notifications - seen: bool, -} - -impl ListDetailsEntry { - pub fn new(label: impl Into) -> Self { - Self { - label: label.into(), - meta: None, - left_content: None, - handlers: ListDetailsEntryHandlers::default(), - actions: None, - seen: false, - } - } - - pub fn meta(mut self, meta: impl Into) -> Self { - self.meta = Some(meta.into()); - self - } - - pub fn seen(mut self, seen: bool) -> Self { - self.seen = seen; - self - } - - pub fn on_click(mut self, handler: ClickHandler) -> Self { - self.handlers.click = Some(handler); - self - } - - pub fn actions(mut self, actions: Vec>) -> Self { - self.actions = Some(actions); - self - } - - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let settings = user_settings(cx); - - let (item_bg, item_bg_hover, item_bg_active) = ( - cx.theme().colors().ghost_element, - cx.theme().colors().ghost_element_hover, - cx.theme().colors().ghost_element_active, - ); - - let label_color = match self.seen { - true => LabelColor::Muted, - false => LabelColor::Default, - }; - - div() - .relative() - .group("") - .bg(item_bg) - .px_2() - .py_1p5() - .w_full() - .z_index(1) - .when(!self.seen, |this| { - this.child( - div() - .absolute() - .left(px(3.0)) - .top_3() - .rounded_full() - .border_2() - .border_color(cx.theme().colors().surface) - .w(px(9.0)) - .h(px(9.0)) - .z_index(2) - .bg(cx.theme().status().info), - ) - }) - .child( - v_stack() - .w_full() - .line_height(relative(1.2)) - .gap_1() - .child( - div() - .w_5() - .h_5() - .rounded_full() - .bg(cx.theme().colors().icon_accent), - ) - .child(Label::new(self.label.clone()).color(label_color)) - .children( - self.meta - .map(|meta| Label::new(meta).color(LabelColor::Muted)), - ) - .child( - h_stack() - .gap_1() - .justify_end() - .children(self.actions.unwrap_or_default()), - ), - ) - } -} - #[derive(Clone, Component)] pub struct ListSeparator; @@ -564,20 +351,22 @@ impl ListSeparator { } #[derive(Component)] -pub struct List { - items: Vec>, +pub struct List { + items: Vec, + /// Message to display when the list is empty + /// Defaults to "No items" empty_message: SharedString, header: Option, - toggleable: Toggleable, + toggle: Toggle, } -impl List { - pub fn new(items: Vec>) -> Self { +impl List { + pub fn new(items: Vec) -> Self { Self { items, empty_message: "No items".into(), header: None, - toggleable: Toggleable::default(), + toggle: Toggle::NotToggleable, } } @@ -591,19 +380,16 @@ impl List { self } - pub fn toggle(mut self, toggle: ToggleState) -> Self { - self.toggleable = toggle.into(); + pub fn toggle(mut self, toggle: Toggle) -> Self { + self.toggle = toggle; self } - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let is_toggleable = self.toggleable != Toggleable::NotToggleable; - let is_toggled = Toggleable::is_toggled(&self.toggleable); - - let list_content = match (self.items.is_empty(), is_toggled) { + fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + let list_content = match (self.items.is_empty(), self.toggle) { (false, _) => div().children(self.items), - (true, false) => div(), - (true, true) => { + (true, Toggle::Toggled(false)) => div(), + (true, _) => { div().child(Label::new(self.empty_message.clone()).color(LabelColor::Muted)) } }; @@ -611,7 +397,7 @@ impl List { v_stack() .w_full() .py_1() - .children(self.header.map(|header| header.toggleable(self.toggleable))) + .children(self.header.map(|header| header)) .child(list_content) } } diff --git a/crates/ui2/src/components/player.rs b/crates/ui2/src/components/player.rs index c7b7ade1c13c62878e8ae72ce828bde30ab9d375..b6c80400cf373dd716cc9cb1686a7aee8af05cc0 100644 --- a/crates/ui2/src/components/player.rs +++ b/crates/ui2/src/components/player.rs @@ -2,6 +2,24 @@ use gpui2::{Hsla, ViewContext}; use crate::prelude::*; +/// Represents a person with a Zed account's public profile. +/// All data in this struct should be considered public. +pub struct PublicPlayer { + pub username: SharedString, + pub avatar: SharedString, + pub is_contact: bool, +} + +impl PublicPlayer { + pub fn new(username: impl Into, avatar: impl Into) -> Self { + Self { + username: username.into(), + avatar: avatar.into(), + is_contact: false, + } + } +} + #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] pub enum PlayerStatus { #[default] diff --git a/crates/ui2/src/components/slot.rs b/crates/ui2/src/components/slot.rs new file mode 100644 index 0000000000000000000000000000000000000000..f980e2fbda51a3b86ae5d677ac5838cb94ea09d2 --- /dev/null +++ b/crates/ui2/src/components/slot.rs @@ -0,0 +1,14 @@ +use gpui2::SharedString; + +use crate::Icon; + +#[derive(Debug, Clone)] +/// A slot utility that provides a way to to pass either +/// an icon or an image to a component. +/// +/// Can be filled with a [] +pub enum GraphicSlot { + Icon(Icon), + Avatar(SharedString), + PublicActor(SharedString), +} diff --git a/crates/ui2/src/components/toggle.rs b/crates/ui2/src/components/toggle.rs new file mode 100644 index 0000000000000000000000000000000000000000..adde36758159cf6a1ea93ec2f152f0dfcf904f6b --- /dev/null +++ b/crates/ui2/src/components/toggle.rs @@ -0,0 +1,61 @@ +use gpui2::{div, Component, ParentElement}; + +use crate::{Icon, IconColor, IconElement, IconSize}; + +/// Whether the entry is toggleable, and if so, whether it is currently toggled. +/// +/// To make an element toggleable, simply add a `Toggle::Toggled(_)` and handle it's cases. +/// +/// You can check if an element is toggleable with `.is_toggleable()` +/// +/// Possible values: +/// - `Toggle::NotToggleable` - The entry is not toggleable +/// - `Toggle::Toggled(true)` - The entry is toggleable and toggled +/// - `Toggle::Toggled(false)` - The entry is toggleable and not toggled +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Toggle { + NotToggleable, + Toggled(bool), +} + +impl Toggle { + /// Returns true if the entry is toggled (or is not toggleable.) + /// + /// As element that isn't toggleable is always "expanded" or "enabled" + /// returning true in that case makes sense. + pub fn is_toggled(&self) -> bool { + match self { + Self::Toggled(false) => false, + _ => true, + } + } + + pub fn is_toggleable(&self) -> bool { + match self { + Self::Toggled(_) => true, + _ => false, + } + } +} + +impl From for Toggle { + fn from(toggled: bool) -> Self { + Toggle::Toggled(toggled) + } +} + +pub fn disclosure_control(toggle: Toggle) -> impl Component { + match (toggle.is_toggleable(), toggle.is_toggled()) { + (false, _) => div(), + (_, true) => div().child( + IconElement::new(Icon::ChevronDown) + .color(IconColor::Muted) + .size(IconSize::Small), + ), + (_, false) => div().child( + IconElement::new(Icon::ChevronRight) + .color(IconColor::Muted) + .size(IconSize::Small), + ), + } +} diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index fbb7ccc528107de3d0eef115ca7fc4ba536a68e2..8ba74cce95cdf59c79d2d323ffe25e9abb22dfff 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -10,24 +10,6 @@ pub use theme2::ActiveTheme; use gpui2::Hsla; use strum::EnumIter; -/// Represents a person with a Zed account's public profile. -/// All data in this struct should be considered public. -pub struct PublicActor { - pub username: SharedString, - pub avatar: SharedString, - pub is_contact: bool, -} - -impl PublicActor { - pub fn new(username: impl Into, avatar: impl Into) -> Self { - Self { - username: username.into(), - avatar: avatar.into(), - is_contact: false, - } - } -} - #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)] pub enum FileSystemStatus { #[default] @@ -179,61 +161,3 @@ pub enum SelectedState { PartiallySelected, Selected, } - -#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] -pub enum Toggleable { - Toggleable(ToggleState), - #[default] - NotToggleable, -} - -impl Toggleable { - pub fn is_toggled(&self) -> bool { - match self { - Self::Toggleable(ToggleState::Toggled) => true, - _ => false, - } - } -} - -impl From for Toggleable { - fn from(state: ToggleState) -> Self { - Self::Toggleable(state) - } -} - -#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] -pub enum ToggleState { - /// The "on" state of a toggleable element. - /// - /// Example: - /// - A collasable list that is currently expanded - /// - A toggle button that is currently on. - Toggled, - /// The "off" state of a toggleable element. - /// - /// Example: - /// - A collasable list that is currently collapsed - /// - A toggle button that is currently off. - #[default] - NotToggled, -} - -impl From for ToggleState { - fn from(toggleable: Toggleable) -> Self { - match toggleable { - Toggleable::Toggleable(state) => state, - Toggleable::NotToggleable => ToggleState::NotToggled, - } - } -} - -impl From for ToggleState { - fn from(toggled: bool) -> Self { - if toggled { - ToggleState::Toggled - } else { - ToggleState::NotToggled - } - } -} diff --git a/crates/ui2/src/static_data.rs b/crates/ui2/src/static_data.rs index 68f625c75d6f2ac24e7caf8e97469a0c082effad..5342e1fb165606a8316fbb542aad2b78104ec4ea 100644 --- a/crates/ui2/src/static_data.rs +++ b/crates/ui2/src/static_data.rs @@ -7,13 +7,13 @@ use gpui2::{AppContext, ViewContext}; use rand::Rng; use theme2::ActiveTheme; +use crate::HighlightedText; use crate::{ Buffer, BufferRow, BufferRows, Button, EditorPane, FileSystemStatus, GitStatus, - HighlightedLine, Icon, Keybinding, Label, LabelColor, ListEntry, ListEntrySize, ListSubHeader, - Livestream, MicStatus, ModifierKeys, Notification, PaletteItem, Player, PlayerCallStatus, - PlayerWithCallStatus, PublicActor, ScreenShareStatus, Symbol, Tab, ToggleState, VideoStatus, + HighlightedLine, Icon, Keybinding, Label, LabelColor, ListEntry, ListEntrySize, Livestream, + MicStatus, ModifierKeys, Notification, PaletteItem, Player, PlayerCallStatus, + PlayerWithCallStatus, PublicPlayer, ScreenShareStatus, Symbol, Tab, Toggle, VideoStatus, }; -use crate::{HighlightedText, ListDetailsEntry}; use crate::{ListItem, NotificationAction}; pub fn static_tabs_example() -> Vec { @@ -345,7 +345,7 @@ pub fn static_new_notification_items_2() -> Vec> { DateTime::parse_from_rfc3339("2023-11-02T12:09:07Z") .unwrap() .naive_local(), - PublicActor::new("as-cii", "http://github.com/as-cii.png?s=50"), + PublicPlayer::new("as-cii", "http://github.com/as-cii.png?s=50"), [ NotificationAction::new( Button::new("Decline"), @@ -374,7 +374,7 @@ pub fn static_new_notification_items_2() -> Vec> { DateTime::parse_from_rfc3339("2023-11-01T12:09:07Z") .unwrap() .naive_local(), - PublicActor::new("as-cii", "http://github.com/as-cii.png?s=50"), + PublicPlayer::new("as-cii", "http://github.com/as-cii.png?s=50"), [ NotificationAction::new( Button::new("Decline"), @@ -403,7 +403,7 @@ pub fn static_new_notification_items_2() -> Vec> { DateTime::parse_from_rfc3339("2022-10-25T12:09:07Z") .unwrap() .naive_local(), - PublicActor::new("as-cii", "http://github.com/as-cii.png?s=50"), + PublicPlayer::new("as-cii", "http://github.com/as-cii.png?s=50"), [ NotificationAction::new( Button::new("Decline"), @@ -432,7 +432,7 @@ pub fn static_new_notification_items_2() -> Vec> { DateTime::parse_from_rfc3339("2021-10-12T12:09:07Z") .unwrap() .naive_local(), - PublicActor::new("as-cii", "http://github.com/as-cii.png?s=50"), + PublicPlayer::new("as-cii", "http://github.com/as-cii.png?s=50"), [ NotificationAction::new( Button::new("Decline"), @@ -461,7 +461,7 @@ pub fn static_new_notification_items_2() -> Vec> { DateTime::parse_from_rfc3339("1969-07-20T00:00:00Z") .unwrap() .naive_local(), - PublicActor::new("as-cii", "http://github.com/as-cii.png?s=50"), + PublicPlayer::new("as-cii", "http://github.com/as-cii.png?s=50"), [ NotificationAction::new( Button::new("Decline"), @@ -478,89 +478,12 @@ pub fn static_new_notification_items_2() -> Vec> { ] } -pub fn static_new_notification_items() -> Vec> { - vec![ - ListItem::Header(ListSubHeader::new("New")), - ListItem::Details( - ListDetailsEntry::new("maxdeviant invited you to join a stream in #design.") - .meta("4 people in stream."), - ), - ListItem::Details(ListDetailsEntry::new( - "nathansobo accepted your contact request.", - )), - ListItem::Header(ListSubHeader::new("Earlier")), - ListItem::Details( - ListDetailsEntry::new("mikaylamaki added you as a contact.").actions(vec![ - Button::new("Decline"), - Button::new("Accept").variant(crate::ButtonVariant::Filled), - ]), - ), - ListItem::Details( - ListDetailsEntry::new("maxdeviant invited you to a stream in #design.") - .seen(true) - .meta("This stream has ended."), - ), - ListItem::Details(ListDetailsEntry::new( - "as-cii accepted your contact request.", - )), - ListItem::Details( - ListDetailsEntry::new("You were added as an admin on the #gpui2 channel.").seen(true), - ), - ListItem::Details(ListDetailsEntry::new( - "osiewicz accepted your contact request.", - )), - ListItem::Details(ListDetailsEntry::new( - "ConradIrwin accepted your contact request.", - )), - ListItem::Details( - ListDetailsEntry::new("nathansobo invited you to a stream in #gpui2.") - .seen(true) - .meta("This stream has ended."), - ), - ListItem::Details(ListDetailsEntry::new( - "nathansobo accepted your contact request.", - )), - ListItem::Header(ListSubHeader::new("Earlier")), - ListItem::Details( - ListDetailsEntry::new("mikaylamaki added you as a contact.").actions(vec![ - Button::new("Decline"), - Button::new("Accept").variant(crate::ButtonVariant::Filled), - ]), - ), - ListItem::Details( - ListDetailsEntry::new("maxdeviant invited you to a stream in #design.") - .seen(true) - .meta("This stream has ended."), - ), - ListItem::Details(ListDetailsEntry::new( - "as-cii accepted your contact request.", - )), - ListItem::Details( - ListDetailsEntry::new("You were added as an admin on the #gpui2 channel.").seen(true), - ), - ListItem::Details(ListDetailsEntry::new( - "osiewicz accepted your contact request.", - )), - ListItem::Details(ListDetailsEntry::new( - "ConradIrwin accepted your contact request.", - )), - ListItem::Details( - ListDetailsEntry::new("nathansobo invited you to a stream in #gpui2.") - .seen(true) - .meta("This stream has ended."), - ), - ] - .into_iter() - .map(From::from) - .collect() -} - -pub fn static_project_panel_project_items() -> Vec> { +pub fn static_project_panel_project_items() -> Vec { vec![ ListEntry::new(Label::new("zed")) .left_icon(Icon::FolderOpen.into()) .indent_level(0) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ListEntry::new(Label::new(".cargo")) .left_icon(Icon::Folder.into()) .indent_level(1), @@ -579,14 +502,14 @@ pub fn static_project_panel_project_items() -> Vec> { ListEntry::new(Label::new("assets")) .left_icon(Icon::Folder.into()) .indent_level(1) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ListEntry::new(Label::new("cargo-target").color(LabelColor::Hidden)) .left_icon(Icon::Folder.into()) .indent_level(1), ListEntry::new(Label::new("crates")) .left_icon(Icon::FolderOpen.into()) .indent_level(1) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ListEntry::new(Label::new("activity_indicator")) .left_icon(Icon::Folder.into()) .indent_level(2), @@ -608,38 +531,38 @@ pub fn static_project_panel_project_items() -> Vec> { ListEntry::new(Label::new("sqlez").color(LabelColor::Modified)) .left_icon(Icon::Folder.into()) .indent_level(2) - .toggle(ToggleState::NotToggled), + .toggle(Toggle::Toggled(false)), ListEntry::new(Label::new("gpui2")) .left_icon(Icon::FolderOpen.into()) .indent_level(2) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ListEntry::new(Label::new("src")) .left_icon(Icon::FolderOpen.into()) .indent_level(3) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ListEntry::new(Label::new("derive_element.rs")) .left_icon(Icon::FileRust.into()) .indent_level(4), ListEntry::new(Label::new("storybook").color(LabelColor::Modified)) .left_icon(Icon::FolderOpen.into()) .indent_level(1) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ListEntry::new(Label::new("docs").color(LabelColor::Default)) .left_icon(Icon::Folder.into()) .indent_level(2) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ListEntry::new(Label::new("src").color(LabelColor::Modified)) .left_icon(Icon::FolderOpen.into()) .indent_level(3) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ListEntry::new(Label::new("ui").color(LabelColor::Modified)) .left_icon(Icon::FolderOpen.into()) .indent_level(4) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ListEntry::new(Label::new("component").color(LabelColor::Created)) .left_icon(Icon::FolderOpen.into()) .indent_level(5) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ListEntry::new(Label::new("facepile.rs").color(LabelColor::Default)) .left_icon(Icon::FileRust.into()) .indent_level(6), @@ -682,7 +605,7 @@ pub fn static_project_panel_project_items() -> Vec> { .collect() } -pub fn static_project_panel_single_items() -> Vec> { +pub fn static_project_panel_single_items() -> Vec { vec![ ListEntry::new(Label::new("todo.md")) .left_icon(Icon::FileDoc.into()) @@ -699,7 +622,7 @@ pub fn static_project_panel_single_items() -> Vec> { .collect() } -pub fn static_collab_panel_current_call() -> Vec> { +pub fn static_collab_panel_current_call() -> Vec { vec![ ListEntry::new(Label::new("as-cii")).left_avatar("http://github.com/as-cii.png?s=50"), ListEntry::new(Label::new("nathansobo")) @@ -712,7 +635,7 @@ pub fn static_collab_panel_current_call() -> Vec> { .collect() } -pub fn static_collab_panel_channels() -> Vec> { +pub fn static_collab_panel_channels() -> Vec { vec![ ListEntry::new(Label::new("zed")) .left_icon(Icon::Hash.into()) diff --git a/crates/ui2/src/to_extract/collab_panel.rs b/crates/ui2/src/to_extract/collab_panel.rs index a0e3b55f63c43c57c37645ae7c4c7492e92f3d03..9019456dd131800efecbd68ac1d8bcabae704090 100644 --- a/crates/ui2/src/to_extract/collab_panel.rs +++ b/crates/ui2/src/to_extract/collab_panel.rs @@ -1,7 +1,6 @@ -use crate::prelude::*; +use crate::{prelude::*, Toggle}; use crate::{ - static_collab_panel_channels, static_collab_panel_current_call, v_stack, Icon, List, - ListHeader, ToggleState, + static_collab_panel_channels, static_collab_panel_current_call, v_stack, Icon, List, ListHeader, }; #[derive(Component)] @@ -34,17 +33,17 @@ impl CollabPanel { .header( ListHeader::new("CRDB") .left_icon(Icon::Hash.into()) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ), ) .child( v_stack().id("channels").py_1().child( List::new(static_collab_panel_channels()) - .header(ListHeader::new("CHANNELS").toggle(ToggleState::Toggled)) + .header(ListHeader::new("CHANNELS").toggle(Toggle::Toggled(true))) .empty_message("No channels yet. Add a channel to get started.") - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ), ) .child( @@ -52,9 +51,9 @@ impl CollabPanel { List::new(static_collab_panel_current_call()) .header( ListHeader::new("CONTACTS – ONLINE") - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ) - .toggle(ToggleState::Toggled), + .toggle(Toggle::Toggled(true)), ), ) .child( @@ -62,9 +61,9 @@ impl CollabPanel { List::new(static_collab_panel_current_call()) .header( ListHeader::new("CONTACTS – OFFLINE") - .toggle(ToggleState::NotToggled), + .toggle(Toggle::Toggled(false)), ) - .toggle(ToggleState::NotToggled), + .toggle(Toggle::Toggled(false)), ), ), ) diff --git a/crates/ui2/src/to_extract/notifications_panel.rs b/crates/ui2/src/to_extract/notifications_panel.rs index 74f015ac068706cd09242dd04f30d8b09e285842..789aa2b0aa11d5f2dded289e1d99ddc433cfae2f 100644 --- a/crates/ui2/src/to_extract/notifications_panel.rs +++ b/crates/ui2/src/to_extract/notifications_panel.rs @@ -1,8 +1,8 @@ use crate::utils::naive_format_distance_from_now; use crate::{ - h_stack, prelude::*, static_new_notification_items_2, v_stack, Avatar, Button, Icon, - IconButton, IconElement, Label, LabelColor, LineHeightStyle, ListHeaderMeta, ListSeparator, - UnreadIndicator, + h_stack, prelude::*, static_new_notification_items_2, v_stack, Avatar, ButtonOrIconButton, + Icon, IconElement, Label, LabelColor, LineHeightStyle, ListHeaderMeta, ListSeparator, + PublicPlayer, UnreadIndicator, }; use crate::{ClickHandler, ListHeader}; @@ -57,23 +57,6 @@ impl NotificationsPanel { } } -pub enum ButtonOrIconButton { - Button(Button), - IconButton(IconButton), -} - -impl From> for ButtonOrIconButton { - fn from(value: Button) -> Self { - Self::Button(value) - } -} - -impl From> for ButtonOrIconButton { - fn from(value: IconButton) -> Self { - Self::IconButton(value) - } -} - pub struct NotificationAction { button: ButtonOrIconButton, tooltip: SharedString, @@ -102,7 +85,7 @@ impl NotificationAction { } pub enum ActorOrIcon { - Actor(PublicActor), + Actor(PublicPlayer), Icon(Icon), } @@ -171,7 +154,7 @@ impl Notification { id: impl Into, message: impl Into, date_received: NaiveDateTime, - actor: PublicActor, + actor: PublicPlayer, click_action: ClickHandler, ) -> Self { Self::new( @@ -210,7 +193,7 @@ impl Notification { id: impl Into, message: impl Into, date_received: NaiveDateTime, - actor: PublicActor, + actor: PublicPlayer, actions: [NotificationAction; 2], ) -> Self { Self::new( diff --git a/crates/ui2/src/to_extract/project_panel.rs b/crates/ui2/src/to_extract/project_panel.rs index 76fa50d3380188b6945fa95e5426071d0baec69c..807768427b21729f1b1bfd6f3cc107cddb67423d 100644 --- a/crates/ui2/src/to_extract/project_panel.rs +++ b/crates/ui2/src/to_extract/project_panel.rs @@ -18,8 +18,7 @@ impl ProjectPanel { .id(self.id.clone()) .flex() .flex_col() - .w_full() - .h_full() + .size_full() .bg(cx.theme().colors().surface) .child( div() @@ -30,15 +29,13 @@ impl ProjectPanel { .overflow_y_scroll() .child( List::new(static_project_panel_single_items()) - .header(ListHeader::new("FILES").toggle(ToggleState::Toggled)) - .empty_message("No files in directory") - .toggle(ToggleState::Toggled), + .header(ListHeader::new("FILES")) + .empty_message("No files in directory"), ) .child( List::new(static_project_panel_project_items()) - .header(ListHeader::new("PROJECT").toggle(ToggleState::Toggled)) - .empty_message("No folders in directory") - .toggle(ToggleState::Toggled), + .header(ListHeader::new("PROJECT")) + .empty_message("No folders in directory"), ), ) .child( From 1bce5dcc69b4b89b9be06142ac7fe843c4bcdf06 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Sun, 5 Nov 2023 01:06:41 -0500 Subject: [PATCH 19/32] Add checkboxes and their stories --- assets/icons/dash.svg | 1 + crates/storybook2/src/story_selector.rs | 2 + crates/theme2/src/colors.rs | 2 + crates/theme2/src/default_colors.rs | 4 + crates/ui2/docs/building-ui.md | 10 ++ crates/ui2/src/components.rs | 2 + crates/ui2/src/components/checkbox.rs | 217 ++++++++++++++++++++++++ crates/ui2/src/components/icon.rs | 4 + crates/ui2/src/prelude.rs | 6 +- 9 files changed, 245 insertions(+), 3 deletions(-) create mode 100644 assets/icons/dash.svg create mode 100644 crates/ui2/src/components/checkbox.rs diff --git a/assets/icons/dash.svg b/assets/icons/dash.svg new file mode 100644 index 0000000000000000000000000000000000000000..efff9eab5e82ac7dfbc9263081fc25fc1eae2551 --- /dev/null +++ b/assets/icons/dash.svg @@ -0,0 +1 @@ + diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index a78705c7bbfd9d68308c793809596e1ea3e729f2..2adf2956d33512930bf8e829a3845d7ba5522dbc 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -19,6 +19,7 @@ pub enum ComponentStory { Buffer, Button, ChatPanel, + Checkbox, CollabPanel, Colors, CommandPalette, @@ -61,6 +62,7 @@ impl ComponentStory { Self::Buffer => cx.build_view(|_| ui::BufferStory).into(), Self::Button => cx.build_view(|_| ButtonStory).into(), Self::ChatPanel => cx.build_view(|_| ui::ChatPanelStory).into(), + Self::Checkbox => cx.build_view(|_| ui::CheckboxStory).into(), Self::CollabPanel => cx.build_view(|_| ui::CollabPanelStory).into(), Self::Colors => cx.build_view(|_| ColorsStory).into(), Self::CommandPalette => cx.build_view(|_| ui::CommandPaletteStory).into(), diff --git a/crates/theme2/src/colors.rs b/crates/theme2/src/colors.rs index b02a9c14dfa77a10146540ac8ec3baeb0e84c929..b9f8804205da9afb4dd8a9c348276c53063fbc30 100644 --- a/crates/theme2/src/colors.rs +++ b/crates/theme2/src/colors.rs @@ -54,7 +54,9 @@ pub struct ThemeColors { pub border: Hsla, pub border_variant: Hsla, pub border_focused: Hsla, + pub border_selected: Hsla, pub border_transparent: Hsla, + pub border_disabled: Hsla, pub elevated_surface: Hsla, pub surface: Hsla, pub background: Hsla, diff --git a/crates/theme2/src/default_colors.rs b/crates/theme2/src/default_colors.rs index 802392d2963389bdf7ef95d66d4022e49cf0760f..4ecae43b1559c223559dce98546310f0b5afc3aa 100644 --- a/crates/theme2/src/default_colors.rs +++ b/crates/theme2/src/default_colors.rs @@ -205,6 +205,8 @@ impl ThemeColors { border: neutral().light().step_6(), border_variant: neutral().light().step_5(), border_focused: blue().light().step_5(), + border_disabled: neutral().light().step_3(), + border_selected: blue().light().step_5(), border_transparent: system.transparent, elevated_surface: neutral().light().step_2(), surface: neutral().light().step_2(), @@ -250,6 +252,8 @@ impl ThemeColors { border: neutral().dark().step_6(), border_variant: neutral().dark().step_5(), border_focused: blue().dark().step_5(), + border_disabled: neutral().dark().step_3(), + border_selected: blue().dark().step_5(), border_transparent: system.transparent, elevated_surface: neutral().dark().step_2(), surface: neutral().dark().step_2(), diff --git a/crates/ui2/docs/building-ui.md b/crates/ui2/docs/building-ui.md index a2a3ff697b1a6a69d7c2a216912dd62a86f0b4c3..e0160e336ed36df3a4354c8e7ba186a035502227 100644 --- a/crates/ui2/docs/building-ui.md +++ b/crates/ui2/docs/building-ui.md @@ -2,6 +2,16 @@ ## Common patterns +### Method ordering + +- id +- Flex properties +- Position properties +- Size properties +- Style properties +- Handlers +- State properties + ### Using the Label Component to Create UI Text The `Label` component helps in displaying text on user interfaces. It creates an interface where specific parameters such as label color, line height style, and strikethrough can be set. diff --git a/crates/ui2/src/components.rs b/crates/ui2/src/components.rs index 692cd55e8ec065831c2e85d8a564e90713c3c798..a8a7ddfd46f803cd9760438edb89a62cc334dfc5 100644 --- a/crates/ui2/src/components.rs +++ b/crates/ui2/src/components.rs @@ -1,5 +1,6 @@ mod avatar; mod button; +mod checkbox; mod context_menu; mod details; mod facepile; @@ -25,6 +26,7 @@ mod tool_divider; pub use avatar::*; pub use button::*; +pub use checkbox::*; pub use context_menu::*; pub use details::*; pub use facepile::*; diff --git a/crates/ui2/src/components/checkbox.rs b/crates/ui2/src/components/checkbox.rs new file mode 100644 index 0000000000000000000000000000000000000000..3add6cebaccc07847310ce1445dc6ecf0a6f635b --- /dev/null +++ b/crates/ui2/src/components/checkbox.rs @@ -0,0 +1,217 @@ +///! # Checkbox +///! +///! Checkboxes are used for multiple choices, not for mutually exclusive choices. +///! Each checkbox works independently from other checkboxes in the list, +///! therefore checking an additional box does not affect any other selections. +use gpui2::{ + div, Component, ParentElement, SharedString, StatelessInteractive, Styled, ViewContext, +}; +use theme2::ActiveTheme; + +use crate::{Icon, IconColor, IconElement, Selected}; + +#[derive(Component)] +pub struct Checkbox { + id: SharedString, + checked: Selected, + disabled: bool, +} + +impl Checkbox { + pub fn new(id: impl Into) -> Self { + Self { + id: id.into(), + checked: Selected::Unselected, + disabled: false, + } + } + + pub fn toggle(mut self) -> Self { + self.checked = match self.checked { + Selected::Selected => Selected::Unselected, + Selected::Unselected => Selected::Selected, + Selected::Indeterminate => Selected::Selected, + }; + self + } + + pub fn set_indeterminate(mut self) -> Self { + self.checked = Selected::Indeterminate; + self + } + + pub fn set_disabled(mut self, disabled: bool) -> Self { + self.disabled = disabled; + self + } + + pub fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + let group_id = format!("checkbox_group_{}", self.id); + + // The icon is different depending on the state of the checkbox. + // + // We need the match to return all the same type, + // so we wrap the eatch result in a div. + // + // We are still exploring the best way to handle this. + let icon = match self.checked { + // When selected, we show a checkmark. + Selected::Selected => { + div().child( + IconElement::new(Icon::Check) + .size(crate::IconSize::Small) + .color( + // If the checkbox is disabled we change the color of the icon. + if self.disabled { + IconColor::Disabled + } else { + IconColor::Selected + }, + ), + ) + } + // In an indeterminate state, we show a dash. + Selected::Indeterminate => { + div().child( + IconElement::new(Icon::Dash) + .size(crate::IconSize::Small) + .color( + // If the checkbox is disabled we change the color of the icon. + if self.disabled { + IconColor::Disabled + } else { + IconColor::Selected + }, + ), + ) + } + // When unselected, we show nothing. + Selected::Unselected => div(), + }; + + // A checkbox could be in an indeterminate state, + // for example the indeterminate state could represent: + // - a group of options of which only some are selected + // - an enabled option that is no longer available + // - a previously agreed to license that has been updated + // + // For the sake of styles we treat the indeterminate state as selected, + // but it's icon will be different. + let selected = + self.checked == Selected::Selected || self.checked == Selected::Indeterminate; + + // We could use something like this to make the checkbox background when selected: + // + // ~~~rust + // ... + // .when(selected, |this| { + // this.bg(cx.theme().colors().element_selected) + // }) + // ~~~ + // + // But we use a match instead here because the checkbox might be disabled, + // and it could be disabled _while_ it is selected, as well as while it is not selected. + let (bg_color, border_color) = match (self.disabled, selected) { + (true, _) => ( + cx.theme().colors().ghost_element_disabled, + cx.theme().colors().border_disabled, + ), + (false, true) => ( + cx.theme().colors().element_selected, + cx.theme().colors().border, + ), + (false, false) => (cx.theme().colors().element, cx.theme().colors().border), + }; + + div() + // Rather than adding `px_1()` to add some space around the checkbox, + // we use a larger parent element to create a slightly larger + // click area for the checkbox. + .size_5() + // Because we've enlarged the click area, we need to create a + // `group` to pass down interaction events to the checkbox. + .group(group_id.clone()) + .child( + div() + .flex() + // This prevent the flex element from growing + // or shrinking in response to any size changes + .flex_none() + // The combo of `justify_center()` and `items_center()` + // is used frequently to center elements in a flex container. + // + // We use this to center the icon in the checkbox. + .justify_center() + .items_center() + .m_1() + .size_4() + .rounded_sm() + .bg(bg_color) + .border() + .border_color(border_color) + // We only want the interaction states to fire when we + // are in a checkbox that isn't disabled. + .when(!self.disabled, |this| { + // Here instead of `hover()` we use `group_hover()` + // to pass it the group id. + this.group_hover(group_id.clone(), |el| { + el.bg(cx.theme().colors().element_hover) + }) + }) + .child(icon), + ) + } +} + +#[cfg(feature = "stories")] +pub use stories::*; + +#[cfg(feature = "stories")] +mod stories { + use super::*; + use crate::{h_stack, Story}; + use gpui2::{Div, Render}; + + pub struct CheckboxStory; + + impl Render for CheckboxStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + Story::container(cx) + .child(Story::title_for::<_, Checkbox>(cx)) + .child(Story::label(cx, "Default")) + .child( + h_stack() + .p_2() + .gap_2() + .rounded_md() + .border() + .border_color(cx.theme().colors().border) + .child(Checkbox::new("checkbox-enabled")) + .child(Checkbox::new("checkbox-intermediate").set_indeterminate()) + .child(Checkbox::new("checkbox-selected").toggle()), + ) + .child(Story::label(cx, "Disabled")) + .child( + h_stack() + .p_2() + .gap_2() + .rounded_md() + .border() + .border_color(cx.theme().colors().border) + .child(Checkbox::new("checkbox-disabled").set_disabled(true)) + .child( + Checkbox::new("checkbox-disabled-intermediate") + .set_disabled(true) + .set_indeterminate(), + ) + .child( + Checkbox::new("checkbox-disabled-selected") + .set_disabled(true) + .toggle(), + ), + ) + } + } +} diff --git a/crates/ui2/src/components/icon.rs b/crates/ui2/src/components/icon.rs index 5885d76101f18ce332e418423afb0f2d1f3d0da8..8075352b303dbea0a14f6764f60338138116a83f 100644 --- a/crates/ui2/src/components/icon.rs +++ b/crates/ui2/src/components/icon.rs @@ -22,6 +22,7 @@ pub enum IconColor { Warning, Success, Info, + Selected, } impl IconColor { @@ -36,6 +37,7 @@ impl IconColor { IconColor::Warning => cx.theme().status().warning, IconColor::Success => cx.theme().status().success, IconColor::Info => cx.theme().status().info, + IconColor::Selected => cx.theme().colors().icon_accent, } } } @@ -55,6 +57,7 @@ pub enum Icon { ChevronRight, ChevronUp, Close, + Dash, Exit, ExclamationTriangle, File, @@ -112,6 +115,7 @@ impl Icon { Icon::ChevronRight => "icons/chevron_right.svg", Icon::ChevronUp => "icons/chevron_up.svg", Icon::Close => "icons/x.svg", + Icon::Dash => "icons/dash.svg", Icon::Exit => "icons/exit.svg", Icon::ExclamationTriangle => "icons/warning.svg", Icon::File => "icons/file.svg", diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index 8ba74cce95cdf59c79d2d323ffe25e9abb22dfff..072ed0006052c402b58b422e918442829f7d8b88 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -154,10 +154,10 @@ impl InteractionState { } } -#[derive(Default, PartialEq)] -pub enum SelectedState { +#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)] +pub enum Selected { #[default] Unselected, - PartiallySelected, + Indeterminate, Selected, } From 660c3371e4fbaceb2d9916b4e988a75999bc8763 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 5 Nov 2023 14:43:54 +0200 Subject: [PATCH 20/32] Refresh all possibly stale diagnostics pat --- crates/diagnostics/src/diagnostics.rs | 134 ++++++++++++++++---------- 1 file changed, 81 insertions(+), 53 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index a3d779531b5690be0dc60808085bc099768df6bd..dc3dc0e061dd1beb4c9927a0ecdd753a8a4b3c7d 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -3,7 +3,7 @@ mod project_diagnostics_settings; mod toolbar_controls; use anyhow::Result; -use collections::{BTreeSet, HashSet}; +use collections::{BTreeSet, HashMap, HashSet}; use editor::{ diagnostic_block_renderer, display_map::{BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock}, @@ -13,7 +13,7 @@ use editor::{ }; use gpui::{ actions, elements::*, fonts::TextStyle, serde_json, AnyViewHandle, AppContext, Entity, - ModelHandle, Task, View, ViewContext, ViewHandle, WeakViewHandle, + ModelHandle, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; use language::{ Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, @@ -28,6 +28,7 @@ use std::{ any::{Any, TypeId}, borrow::Cow, cmp::Ordering, + mem, ops::Range, path::PathBuf, sync::Arc, @@ -61,7 +62,9 @@ struct ProjectDiagnosticsEditor { excerpts: ModelHandle, path_states: Vec, paths_to_update: BTreeSet<(ProjectPath, LanguageServerId)>, + current_diagnostics: HashMap>, include_warnings: bool, + _subscriptions: Vec, } struct PathState { @@ -149,25 +152,22 @@ impl ProjectDiagnosticsEditor { workspace: WeakViewHandle, cx: &mut ViewContext, ) -> Self { - cx.subscribe(&project_handle, |this, _, event, cx| match event { - project::Event::DiskBasedDiagnosticsFinished { language_server_id } => { - log::debug!("Disk based diagnostics finished for server {language_server_id}"); - this.update_excerpts(Some(*language_server_id), cx); - this.update_title(cx); - } - project::Event::DiagnosticsUpdated { - language_server_id, - path, - } => { - log::debug!("Adding path {path:?} to update for server {language_server_id}"); - this.paths_to_update - .insert((path.clone(), *language_server_id)); - this.update_excerpts(Some(*language_server_id), cx); - this.update_title(cx); - } - _ => {} - }) - .detach(); + let project_event_subscription = + cx.subscribe(&project_handle, |this, _, event, cx| match event { + project::Event::DiskBasedDiagnosticsFinished { language_server_id } => { + log::debug!("Disk based diagnostics finished for server {language_server_id}"); + this.update_excerpts(Some(*language_server_id), cx); + } + project::Event::DiagnosticsUpdated { + language_server_id, + path, + } => { + log::debug!("Adding path {path:?} to update for server {language_server_id}"); + this.paths_to_update + .insert((path.clone(), *language_server_id)); + } + _ => {} + }); let excerpts = cx.add_model(|cx| MultiBuffer::new(project_handle.read(cx).replica_id())); let editor = cx.add_view(|cx| { @@ -176,19 +176,14 @@ impl ProjectDiagnosticsEditor { editor.set_vertical_scroll_margin(5, cx); editor }); - cx.subscribe(&editor, |this, _, event, cx| { + let editor_event_subscription = cx.subscribe(&editor, |this, _, event, cx| { cx.emit(event.clone()); if event == &editor::Event::Focused && this.path_states.is_empty() { cx.focus_self() } - }) - .detach(); + }); let project = project_handle.read(cx); - let paths_to_update = project - .diagnostic_summaries(cx) - .map(|(path, server_id, _)| (path, server_id)) - .collect(); let summary = project.diagnostic_summary(cx); let mut this = Self { project: project_handle, @@ -197,8 +192,10 @@ impl ProjectDiagnosticsEditor { excerpts, editor, path_states: Default::default(), - paths_to_update, + paths_to_update: BTreeSet::new(), include_warnings: settings::get::(cx).include_warnings, + current_diagnostics: HashMap::default(), + _subscriptions: vec![project_event_subscription, editor_event_subscription], }; this.update_excerpts(None, cx); this @@ -218,12 +215,6 @@ impl ProjectDiagnosticsEditor { fn toggle_warnings(&mut self, _: &ToggleWarnings, cx: &mut ViewContext) { self.include_warnings = !self.include_warnings; - self.paths_to_update = self - .project - .read(cx) - .diagnostic_summaries(cx) - .map(|(path, server_id, _)| (path, server_id)) - .collect(); self.update_excerpts(None, cx); cx.notify(); } @@ -234,29 +225,71 @@ impl ProjectDiagnosticsEditor { cx: &mut ViewContext, ) { log::debug!("Updating excerpts for server {language_server_id:?}"); - let mut paths = Vec::new(); - self.paths_to_update.retain(|(path, server_id)| { - if language_server_id - .map_or(true, |language_server_id| language_server_id == *server_id) - { - paths.push(path.clone()); - false - } else { - true + let mut paths_to_recheck = HashSet::default(); + let mut new_summaries: HashMap> = self + .project + .read(cx) + .diagnostic_summaries(cx) + .fold(HashMap::default(), |mut summaries, (path, server_id, _)| { + summaries.entry(server_id).or_default().insert(path); + summaries + }); + let mut old_diagnostics = + mem::replace(&mut self.current_diagnostics, new_summaries.clone()); + if let Some(language_server_id) = language_server_id { + new_summaries.retain(|server_id, _| server_id == &language_server_id); + old_diagnostics.retain(|server_id, _| server_id == &language_server_id); + self.paths_to_update.retain(|(path, server_id)| { + if server_id == &language_server_id { + paths_to_recheck.insert(path.clone()); + false + } else { + true + } + }); + } else { + paths_to_recheck.extend( + mem::replace(&mut self.paths_to_update, BTreeSet::new()) + .into_iter() + .map(|(path, _)| path), + ); + } + + for (server_id, new_paths) in new_summaries { + match old_diagnostics.remove(&server_id) { + Some(mut old_paths) => { + paths_to_recheck.extend( + new_paths + .into_iter() + .filter(|new_path| !old_paths.remove(new_path)), + ); + paths_to_recheck.extend(old_paths); + } + None => paths_to_recheck.extend(new_paths), } - }); + } + paths_to_recheck.extend(old_diagnostics.into_iter().flat_map(|(_, paths)| paths)); + let project = self.project.clone(); cx.spawn(|this, mut cx| { async move { - for path in paths { + let mut changed = false; + for path in paths_to_recheck { let buffer = project .update(&mut cx, |project, cx| project.open_buffer(path.clone(), cx)) .await?; this.update(&mut cx, |this, cx| { - this.populate_excerpts(path, language_server_id, buffer, cx) + this.populate_excerpts(path, language_server_id, buffer, cx); + changed = true; + })?; + } + if changed { + this.update(&mut cx, |this, cx| { + this.summary = this.project.read(cx).diagnostic_summary(cx); + cx.emit(Event::TitleChanged); })?; } - Result::<_, anyhow::Error>::Ok(()) + anyhow::Ok(()) } .log_err() }) @@ -559,11 +592,6 @@ impl ProjectDiagnosticsEditor { } cx.notify(); } - - fn update_title(&mut self, cx: &mut ViewContext) { - self.summary = self.project.read(cx).diagnostic_summary(cx); - cx.emit(Event::TitleChanged); - } } impl Item for ProjectDiagnosticsEditor { From 7145fabb6d3f727fd260eb33be0220d9cc848c63 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 5 Nov 2023 14:44:22 +0200 Subject: [PATCH 21/32] Eagerly refresh diagnostics that do not intercept with user input --- crates/diagnostics/src/diagnostics.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index dc3dc0e061dd1beb4c9927a0ecdd753a8a4b3c7d..4f66513f0f92d8b06b1f90aa6f5000b076fa5d35 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -165,6 +165,12 @@ impl ProjectDiagnosticsEditor { log::debug!("Adding path {path:?} to update for server {language_server_id}"); this.paths_to_update .insert((path.clone(), *language_server_id)); + let no_multiselections = this.editor.update(cx, |editor, cx| { + editor.selections.all::(cx).len() <= 1 + }); + if no_multiselections && !this.is_dirty(cx) { + this.update_excerpts(Some(*language_server_id), cx); + } } _ => {} }); From ff1d692e4602df3e0459330e793e6ee744a0c544 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 5 Nov 2023 14:53:13 +0200 Subject: [PATCH 22/32] Restructure inner path data --- crates/diagnostics/src/diagnostics.rs | 29 ++++++++++++++------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 4f66513f0f92d8b06b1f90aa6f5000b076fa5d35..a3d4bc958980603808099a21ca4379f782981575 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -3,7 +3,7 @@ mod project_diagnostics_settings; mod toolbar_controls; use anyhow::Result; -use collections::{BTreeSet, HashMap, HashSet}; +use collections::{HashMap, HashSet}; use editor::{ diagnostic_block_renderer, display_map::{BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock}, @@ -61,7 +61,7 @@ struct ProjectDiagnosticsEditor { summary: DiagnosticSummary, excerpts: ModelHandle, path_states: Vec, - paths_to_update: BTreeSet<(ProjectPath, LanguageServerId)>, + paths_to_update: HashMap>, current_diagnostics: HashMap>, include_warnings: bool, _subscriptions: Vec, @@ -128,9 +128,12 @@ impl View for ProjectDiagnosticsEditor { "summary": project.diagnostic_summary(cx), }), "summary": self.summary, - "paths_to_update": self.paths_to_update.iter().map(|(path, server_id)| - (path.path.to_string_lossy(), server_id.0) - ).collect::>(), + "paths_to_update": self.paths_to_update.iter().map(|(server_id, paths)| + (server_id.0, paths.into_iter().map(|path| path.path.to_string_lossy()).collect::>()) + ).collect::>(), + "current_diagnostics": self.current_diagnostics.iter().map(|(server_id, paths)| + (server_id.0, paths.into_iter().map(|path| path.path.to_string_lossy()).collect::>()) + ).collect::>(), "paths_states": self.path_states.iter().map(|state| json!({ "path": state.path.path.to_string_lossy(), @@ -164,7 +167,9 @@ impl ProjectDiagnosticsEditor { } => { log::debug!("Adding path {path:?} to update for server {language_server_id}"); this.paths_to_update - .insert((path.clone(), *language_server_id)); + .entry(*language_server_id) + .or_default() + .insert(path.clone()); let no_multiselections = this.editor.update(cx, |editor, cx| { editor.selections.all::(cx).len() <= 1 }); @@ -198,7 +203,7 @@ impl ProjectDiagnosticsEditor { excerpts, editor, path_states: Default::default(), - paths_to_update: BTreeSet::new(), + paths_to_update: HashMap::default(), include_warnings: settings::get::(cx).include_warnings, current_diagnostics: HashMap::default(), _subscriptions: vec![project_event_subscription, editor_event_subscription], @@ -245,20 +250,16 @@ impl ProjectDiagnosticsEditor { if let Some(language_server_id) = language_server_id { new_summaries.retain(|server_id, _| server_id == &language_server_id); old_diagnostics.retain(|server_id, _| server_id == &language_server_id); - self.paths_to_update.retain(|(path, server_id)| { + self.paths_to_update.retain(|server_id, paths| { if server_id == &language_server_id { - paths_to_recheck.insert(path.clone()); + paths_to_recheck.extend(paths.drain()); false } else { true } }); } else { - paths_to_recheck.extend( - mem::replace(&mut self.paths_to_update, BTreeSet::new()) - .into_iter() - .map(|(path, _)| path), - ); + paths_to_recheck.extend(self.paths_to_update.drain().flat_map(|(_, paths)| paths)); } for (server_id, new_paths) in new_summaries { From fdcb907644e598716c061c1c20edcab19ea79b51 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 5 Nov 2023 15:06:39 +0200 Subject: [PATCH 23/32] Parallelize diagnostics filling, add more logs --- Cargo.lock | 1 + crates/diagnostics/Cargo.toml | 1 + crates/diagnostics/src/diagnostics.rs | 50 ++++++++++++++++++--------- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e33edf29f0076a66e8c622558cfacdbb237c3b6c..b63c46ce987aba6ea2845747d92713c247cd72cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2459,6 +2459,7 @@ dependencies = [ "client", "collections", "editor", + "futures 0.3.28", "gpui", "language", "log", diff --git a/crates/diagnostics/Cargo.toml b/crates/diagnostics/Cargo.toml index 26a2a82999d2374e65ce5e061ee23ab91c366455..0f9d108831b76a370dd1af25d93a533a1dfa46f8 100644 --- a/crates/diagnostics/Cargo.toml +++ b/crates/diagnostics/Cargo.toml @@ -22,6 +22,7 @@ workspace = { path = "../workspace" } log.workspace = true anyhow.workspace = true +futures.workspace = true schemars.workspace = true serde.workspace = true serde_derive.workspace = true diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index a3d4bc958980603808099a21ca4379f782981575..dec26f12c43b3782012d7a49168604ae7aa9dbf1 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -2,7 +2,7 @@ pub mod items; mod project_diagnostics_settings; mod toolbar_controls; -use anyhow::Result; +use anyhow::{Context, Result}; use collections::{HashMap, HashSet}; use editor::{ diagnostic_block_renderer, @@ -11,6 +11,7 @@ use editor::{ scroll::autoscroll::Autoscroll, Editor, ExcerptId, ExcerptRange, MultiBuffer, ToOffset, }; +use futures::future::try_join_all; use gpui::{ actions, elements::*, fonts::TextStyle, serde_json, AnyViewHandle, AppContext, Entity, ModelHandle, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, @@ -277,25 +278,40 @@ impl ProjectDiagnosticsEditor { } paths_to_recheck.extend(old_diagnostics.into_iter().flat_map(|(_, paths)| paths)); + if paths_to_recheck.is_empty() { + log::debug!("No paths to recheck for language server {language_server_id:?}"); + return; + } + + log::debug!( + "Rechecking {} paths for language server {:?}", + paths_to_recheck.len(), + language_server_id + ); let project = self.project.clone(); cx.spawn(|this, mut cx| { async move { - let mut changed = false; - for path in paths_to_recheck { - let buffer = project - .update(&mut cx, |project, cx| project.open_buffer(path.clone(), cx)) - .await?; - this.update(&mut cx, |this, cx| { - this.populate_excerpts(path, language_server_id, buffer, cx); - changed = true; - })?; - } - if changed { - this.update(&mut cx, |this, cx| { - this.summary = this.project.read(cx).diagnostic_summary(cx); - cx.emit(Event::TitleChanged); - })?; - } + let _ = try_join_all(paths_to_recheck.into_iter().map(|path| { + let mut cx = cx.clone(); + let project = project.clone(); + async move { + let buffer = project + .update(&mut cx, |project, cx| project.open_buffer(path.clone(), cx)) + .await + .with_context(|| format!("opening buffer for path {path:?}"))?; + this.update(&mut cx, |this, cx| { + this.populate_excerpts(path, language_server_id, buffer, cx); + }) + .context("missing project")?; + anyhow::Ok(()) + } + })) + .await?; + + this.update(&mut cx, |this, cx| { + this.summary = this.project.read(cx).diagnostic_summary(cx); + cx.emit(Event::TitleChanged); + })?; anyhow::Ok(()) } .log_err() From ad93d9132f03ad398018332f450c541142ba0a75 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 5 Nov 2023 15:37:11 +0200 Subject: [PATCH 24/32] Correctly update old diagnostics --- crates/diagnostics/src/diagnostics.rs | 29 ++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index dec26f12c43b3782012d7a49168604ae7aa9dbf1..1ec4105fbdaf9c02fbadea88c02263c953795371 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -246,11 +246,8 @@ impl ProjectDiagnosticsEditor { summaries.entry(server_id).or_default().insert(path); summaries }); - let mut old_diagnostics = - mem::replace(&mut self.current_diagnostics, new_summaries.clone()); - if let Some(language_server_id) = language_server_id { + let mut old_diagnostics = if let Some(language_server_id) = language_server_id { new_summaries.retain(|server_id, _| server_id == &language_server_id); - old_diagnostics.retain(|server_id, _| server_id == &language_server_id); self.paths_to_update.retain(|server_id, paths| { if server_id == &language_server_id { paths_to_recheck.extend(paths.drain()); @@ -259,10 +256,24 @@ impl ProjectDiagnosticsEditor { true } }); + let mut old_diagnostics = HashMap::default(); + if let Some(new_paths) = new_summaries.get(&language_server_id) { + if let Some(old_paths) = self + .current_diagnostics + .insert(language_server_id, new_paths.clone()) + { + old_diagnostics.insert(language_server_id, old_paths); + } + } else { + if let Some(old_paths) = self.current_diagnostics.remove(&language_server_id) { + old_diagnostics.insert(language_server_id, old_paths); + } + } + old_diagnostics } else { paths_to_recheck.extend(self.paths_to_update.drain().flat_map(|(_, paths)| paths)); - } - + mem::replace(&mut self.current_diagnostics, new_summaries.clone()) + }; for (server_id, new_paths) in new_summaries { match old_diagnostics.remove(&server_id) { Some(mut old_paths) => { @@ -282,7 +293,6 @@ impl ProjectDiagnosticsEditor { log::debug!("No paths to recheck for language server {language_server_id:?}"); return; } - log::debug!( "Rechecking {} paths for language server {:?}", paths_to_recheck.len(), @@ -291,7 +301,7 @@ impl ProjectDiagnosticsEditor { let project = self.project.clone(); cx.spawn(|this, mut cx| { async move { - let _ = try_join_all(paths_to_recheck.into_iter().map(|path| { + let _: Vec<()> = try_join_all(paths_to_recheck.into_iter().map(|path| { let mut cx = cx.clone(); let project = project.clone(); async move { @@ -306,7 +316,8 @@ impl ProjectDiagnosticsEditor { anyhow::Ok(()) } })) - .await?; + .await + .context("rechecking diagnostics for paths")?; this.update(&mut cx, |this, cx| { this.summary = this.project.read(cx).diagnostic_summary(cx); From 7374ca999bbb792d72f76c69b63979d92026afc3 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Sun, 5 Nov 2023 22:56:35 +0100 Subject: [PATCH 25/32] chore: Update vue.js parser (fixes wonky HTML parsing) Vue.js defined a bunch of symbols in it's scanner that collided with those defined in HTML Tree-sitter grammar. I simply removed them as they were meant for consumption by the external parties interested in HTML parser with Vue support - since we handle that ourselves this is not really necessary to preserve anymore. cc was firing up a bunch of warnings about unused symbols, so yeah. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e33edf29f0076a66e8c622558cfacdbb237c3b6c..5c0b98c6e48ed5e74b797d68e07f1bc49fba1f81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9728,7 +9728,7 @@ dependencies = [ [[package]] name = "tree-sitter-vue" version = "0.0.1" -source = "git+https://github.com/zed-industries/tree-sitter-vue?rev=95b2890#95b28908d90e928c308866f7631e73ef6e1d4b5f" +source = "git+https://github.com/zed-industries/tree-sitter-vue?rev=9b6cb221ccb8d0b956fcb17e9a1efac2feefeb58#9b6cb221ccb8d0b956fcb17e9a1efac2feefeb58" dependencies = [ "cc", "tree-sitter", diff --git a/Cargo.toml b/Cargo.toml index 772773c977b4f56b5d6cf0ce3206ef5b31b26c16..6245889530bcefc9ea01a42efb49c1365859eb1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -176,7 +176,7 @@ tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", tree-sitter-lua = "0.0.14" tree-sitter-nix = { git = "https://github.com/nix-community/tree-sitter-nix", rev = "66e3e9ce9180ae08fc57372061006ef83f0abde7" } tree-sitter-nu = { git = "https://github.com/nushell/tree-sitter-nu", rev = "786689b0562b9799ce53e824cb45a1a2a04dc673"} -tree-sitter-vue = {git = "https://github.com/zed-industries/tree-sitter-vue", rev = "95b2890"} +tree-sitter-vue = {git = "https://github.com/zed-industries/tree-sitter-vue", rev = "9b6cb221ccb8d0b956fcb17e9a1efac2feefeb58"} [patch.crates-io] tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "35a6052fbcafc5e5fc0f9415b8652be7dcaf7222" } async-task = { git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e" } From dbdb5f65190a3a2fd787c22a59ad5d77c8ef6ca3 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 30 Oct 2023 13:31:21 -0400 Subject: [PATCH 26/32] Actually find downloaded binary in Elixir cached binary method --- crates/zed/src/languages/elixir.rs | 32 +++++++++++++----------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/crates/zed/src/languages/elixir.rs b/crates/zed/src/languages/elixir.rs index df438d89eef7b7c5c89a376670d7d270db4fa413..e2c79570bcbb444cc056712dfcc45c9ecbf4ea49 100644 --- a/crates/zed/src/languages/elixir.rs +++ b/crates/zed/src/languages/elixir.rs @@ -140,8 +140,8 @@ impl LspAdapter for ElixirLspAdapter { ) -> Result { let version = version.downcast::().unwrap(); let zip_path = container_dir.join(format!("elixir-ls_{}.zip", version.name)); - let version_dir = container_dir.join(format!("elixir-ls_{}", version.name)); - let binary_path = version_dir.join("language_server.sh"); + let folder_path = container_dir.join("elixir-ls"); + let binary_path = folder_path.join("language_server.sh"); if fs::metadata(&binary_path).await.is_err() { let mut response = delegate @@ -160,13 +160,13 @@ impl LspAdapter for ElixirLspAdapter { } futures::io::copy(response.body_mut(), &mut file).await?; - fs::create_dir_all(&version_dir) + fs::create_dir_all(&folder_path) .await - .with_context(|| format!("failed to create directory {}", version_dir.display()))?; + .with_context(|| format!("failed to create directory {}", folder_path.display()))?; let unzip_status = smol::process::Command::new("unzip") .arg(&zip_path) .arg("-d") - .arg(&version_dir) + .arg(&folder_path) .output() .await? .status; @@ -174,7 +174,7 @@ impl LspAdapter for ElixirLspAdapter { Err(anyhow!("failed to unzip elixir-ls archive"))?; } - remove_matching(&container_dir, |entry| entry != version_dir).await; + remove_matching(&container_dir, |entry| entry != folder_path).await; } Ok(LanguageServerBinary { @@ -285,20 +285,16 @@ impl LspAdapter for ElixirLspAdapter { async fn get_cached_server_binary_elixir_ls( container_dir: PathBuf, ) -> Option { - (|| async move { - let mut last = None; - let mut entries = fs::read_dir(&container_dir).await?; - while let Some(entry) = entries.next().await { - last = Some(entry?.path()); - } - last.map(|path| LanguageServerBinary { - path, + let server_path = container_dir.join("elixir-ls/language_server.sh"); + if server_path.exists() { + Some(LanguageServerBinary { + path: server_path, arguments: vec![], }) - .ok_or_else(|| anyhow!("no cached binary")) - })() - .await - .log_err() + } else { + log::error!("missing executable in directory {:?}", server_path); + None + } } pub struct NextLspAdapter; From 66b967532ff730ef778d9bc0a25fa82b465fa3f9 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 6 Nov 2023 11:31:31 -0500 Subject: [PATCH 27/32] zed2: Actually find downloaded binary in Elixir cached binary method --- crates/zed2/src/languages/elixir.rs | 32 +++++++++++++---------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/crates/zed2/src/languages/elixir.rs b/crates/zed2/src/languages/elixir.rs index bd38377c99c17f9fc11e8a2f44044c5d44126c6f..90352c78b49874ab1f76ad73b17f2687baeee8f3 100644 --- a/crates/zed2/src/languages/elixir.rs +++ b/crates/zed2/src/languages/elixir.rs @@ -140,8 +140,8 @@ impl LspAdapter for ElixirLspAdapter { ) -> Result { let version = version.downcast::().unwrap(); let zip_path = container_dir.join(format!("elixir-ls_{}.zip", version.name)); - let version_dir = container_dir.join(format!("elixir-ls_{}", version.name)); - let binary_path = version_dir.join("language_server.sh"); + let folder_path = container_dir.join("elixir-ls"); + let binary_path = folder_path.join("language_server.sh"); if fs::metadata(&binary_path).await.is_err() { let mut response = delegate @@ -160,13 +160,13 @@ impl LspAdapter for ElixirLspAdapter { } futures::io::copy(response.body_mut(), &mut file).await?; - fs::create_dir_all(&version_dir) + fs::create_dir_all(&folder_path) .await - .with_context(|| format!("failed to create directory {}", version_dir.display()))?; + .with_context(|| format!("failed to create directory {}", folder_path.display()))?; let unzip_status = smol::process::Command::new("unzip") .arg(&zip_path) .arg("-d") - .arg(&version_dir) + .arg(&folder_path) .output() .await? .status; @@ -174,7 +174,7 @@ impl LspAdapter for ElixirLspAdapter { Err(anyhow!("failed to unzip elixir-ls archive"))?; } - remove_matching(&container_dir, |entry| entry != version_dir).await; + remove_matching(&container_dir, |entry| entry != folder_path).await; } Ok(LanguageServerBinary { @@ -285,20 +285,16 @@ impl LspAdapter for ElixirLspAdapter { async fn get_cached_server_binary_elixir_ls( container_dir: PathBuf, ) -> Option { - (|| async move { - let mut last = None; - let mut entries = fs::read_dir(&container_dir).await?; - while let Some(entry) = entries.next().await { - last = Some(entry?.path()); - } - last.map(|path| LanguageServerBinary { - path, + let server_path = container_dir.join("elixir-ls/language_server.sh"); + if server_path.exists() { + Some(LanguageServerBinary { + path: server_path, arguments: vec![], }) - .ok_or_else(|| anyhow!("no cached binary")) - })() - .await - .log_err() + } else { + log::error!("missing executable in directory {:?}", server_path); + None + } } pub struct NextLspAdapter; From bf80c1da5bb7405008f73596a270c539d0e41a94 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Mon, 6 Nov 2023 17:53:27 +0100 Subject: [PATCH 28/32] Rename fields in `ThemeColors` (#3242) This PR applies a number of field renames in the `ThemeColors` struct from the `import-theme` branch. This will help prevent this branch from diverging too far from `main`. Release Notes: - N/A --------- Co-authored-by: Nate Butler Co-authored-by: Marshall Bowers <1486634+maxdeviant@users.noreply.github.com> --- crates/theme2/src/colors.rs | 41 +++++++--- crates/theme2/src/default_colors.rs | 82 +++++++++++++------ crates/theme2/src/theme2.rs | 2 +- crates/theme2/src/themes/.gitkeep | 0 crates/ui2/src/components/button.rs | 4 +- crates/ui2/src/components/checkbox.rs | 5 +- crates/ui2/src/components/context_menu.rs | 2 +- crates/ui2/src/components/icon_button.rs | 4 +- crates/ui2/src/components/indicator.rs | 2 +- crates/ui2/src/components/input.rs | 4 +- crates/ui2/src/components/keybinding.rs | 2 +- crates/ui2/src/components/list.rs | 4 +- .../ui2/src/components/notification_toast.rs | 2 +- crates/ui2/src/components/palette.rs | 9 +- crates/ui2/src/components/panel.rs | 2 +- crates/ui2/src/components/tab.rs | 4 +- crates/ui2/src/components/toast.rs | 2 +- crates/ui2/src/to_extract/buffer.rs | 2 +- crates/ui2/src/to_extract/buffer_search.rs | 21 +++-- crates/ui2/src/to_extract/collab_panel.rs | 2 +- crates/ui2/src/to_extract/multi_buffer.rs | 2 +- .../ui2/src/to_extract/notifications_panel.rs | 4 +- crates/ui2/src/to_extract/panes.rs | 2 +- crates/ui2/src/to_extract/project_panel.rs | 2 +- crates/ui2/src/to_extract/status_bar.rs | 2 +- crates/ui2/src/to_extract/tab_bar.rs | 2 +- crates/ui2/src/to_extract/terminal.rs | 2 +- crates/ui2/src/to_extract/toolbar.rs | 2 +- crates/ui2/src/to_extract/traffic_lights.rs | 2 +- crates/workspace2/src/pane.rs | 6 +- crates/workspace2/src/status_bar.rs | 2 +- crates/workspace2/src/workspace2.rs | 2 +- 32 files changed, 144 insertions(+), 82 deletions(-) create mode 100644 crates/theme2/src/themes/.gitkeep diff --git a/crates/theme2/src/colors.rs b/crates/theme2/src/colors.rs index b9f8804205da9afb4dd8a9c348276c53063fbc30..1a1fd2e99ec5f568b06cec93cbdb86ea8ae91296 100644 --- a/crates/theme2/src/colors.rs +++ b/crates/theme2/src/colors.rs @@ -57,17 +57,17 @@ pub struct ThemeColors { pub border_selected: Hsla, pub border_transparent: Hsla, pub border_disabled: Hsla, - pub elevated_surface: Hsla, - pub surface: Hsla, + pub elevated_surface_background: Hsla, + pub surface_background: Hsla, pub background: Hsla, - pub element: Hsla, + pub element_background: Hsla, pub element_hover: Hsla, pub element_active: Hsla, pub element_selected: Hsla, pub element_disabled: Hsla, pub element_placeholder: Hsla, pub element_drop_target: Hsla, - pub ghost_element: Hsla, + pub ghost_element_background: Hsla, pub ghost_element_hover: Hsla, pub ghost_element_active: Hsla, pub ghost_element_selected: Hsla, @@ -82,15 +82,32 @@ pub struct ThemeColors { pub icon_disabled: Hsla, pub icon_placeholder: Hsla, pub icon_accent: Hsla, - pub status_bar: Hsla, - pub title_bar: Hsla, - pub toolbar: Hsla, - pub tab_bar: Hsla, - pub tab_inactive: Hsla, - pub tab_active: Hsla, - pub editor: Hsla, - pub editor_subheader: Hsla, + pub status_bar_background: Hsla, + pub title_bar_background: Hsla, + pub toolbar_background: Hsla, + pub tab_bar_background: Hsla, + pub tab_inactive_background: Hsla, + pub tab_active_background: Hsla, + pub editor_background: Hsla, + pub editor_subheader_background: Hsla, pub editor_active_line: Hsla, + pub terminal_background: Hsla, + pub terminal_ansi_bright_black: Hsla, + pub terminal_ansi_bright_red: Hsla, + pub terminal_ansi_bright_green: Hsla, + pub terminal_ansi_bright_yellow: Hsla, + pub terminal_ansi_bright_blue: Hsla, + pub terminal_ansi_bright_magenta: Hsla, + pub terminal_ansi_bright_cyan: Hsla, + pub terminal_ansi_bright_white: Hsla, + pub terminal_ansi_black: Hsla, + pub terminal_ansi_red: Hsla, + pub terminal_ansi_green: Hsla, + pub terminal_ansi_yellow: Hsla, + pub terminal_ansi_blue: Hsla, + pub terminal_ansi_magenta: Hsla, + pub terminal_ansi_cyan: Hsla, + pub terminal_ansi_white: Hsla, } #[derive(Refineable, Clone)] diff --git a/crates/theme2/src/default_colors.rs b/crates/theme2/src/default_colors.rs index 4ecae43b1559c223559dce98546310f0b5afc3aa..53e34acf1608003d20760ee750e6d449fbd11b43 100644 --- a/crates/theme2/src/default_colors.rs +++ b/crates/theme2/src/default_colors.rs @@ -208,17 +208,17 @@ impl ThemeColors { border_disabled: neutral().light().step_3(), border_selected: blue().light().step_5(), border_transparent: system.transparent, - elevated_surface: neutral().light().step_2(), - surface: neutral().light().step_2(), + elevated_surface_background: neutral().light().step_2(), + surface_background: neutral().light().step_2(), background: neutral().light().step_1(), - element: neutral().light().step_3(), + element_background: neutral().light().step_3(), element_hover: neutral().light().step_4(), element_active: neutral().light().step_5(), element_selected: neutral().light().step_5(), element_disabled: neutral().light_alpha().step_3(), element_placeholder: neutral().light().step_11(), element_drop_target: blue().light_alpha().step_2(), - ghost_element: system.transparent, + ghost_element_background: system.transparent, ghost_element_hover: neutral().light().step_4(), ghost_element_active: neutral().light().step_5(), ghost_element_selected: neutral().light().step_5(), @@ -233,15 +233,32 @@ impl ThemeColors { icon_disabled: neutral().light().step_9(), icon_placeholder: neutral().light().step_10(), icon_accent: blue().light().step_11(), - status_bar: neutral().light().step_2(), - title_bar: neutral().light().step_2(), - toolbar: neutral().light().step_1(), - tab_bar: neutral().light().step_2(), - tab_active: neutral().light().step_1(), - tab_inactive: neutral().light().step_2(), - editor: neutral().light().step_1(), - editor_subheader: neutral().light().step_2(), + status_bar_background: neutral().light().step_2(), + title_bar_background: neutral().light().step_2(), + toolbar_background: neutral().light().step_1(), + tab_bar_background: neutral().light().step_2(), + tab_active_background: neutral().light().step_1(), + tab_inactive_background: neutral().light().step_2(), + editor_background: neutral().light().step_1(), + editor_subheader_background: neutral().light().step_2(), editor_active_line: neutral().light_alpha().step_3(), + terminal_background: neutral().light().step_1(), + terminal_ansi_black: black().light().step_12(), + terminal_ansi_red: red().light().step_11(), + terminal_ansi_green: green().light().step_11(), + terminal_ansi_yellow: yellow().light().step_11(), + terminal_ansi_blue: blue().light().step_11(), + terminal_ansi_magenta: violet().light().step_11(), + terminal_ansi_cyan: cyan().light().step_11(), + terminal_ansi_white: neutral().light().step_12(), + terminal_ansi_bright_black: black().light().step_11(), + terminal_ansi_bright_red: red().light().step_10(), + terminal_ansi_bright_green: green().light().step_10(), + terminal_ansi_bright_yellow: yellow().light().step_10(), + terminal_ansi_bright_blue: blue().light().step_10(), + terminal_ansi_bright_magenta: violet().light().step_10(), + terminal_ansi_bright_cyan: cyan().light().step_10(), + terminal_ansi_bright_white: neutral().light().step_11(), } } @@ -255,17 +272,17 @@ impl ThemeColors { border_disabled: neutral().dark().step_3(), border_selected: blue().dark().step_5(), border_transparent: system.transparent, - elevated_surface: neutral().dark().step_2(), - surface: neutral().dark().step_2(), + elevated_surface_background: neutral().dark().step_2(), + surface_background: neutral().dark().step_2(), background: neutral().dark().step_1(), - element: neutral().dark().step_3(), + element_background: neutral().dark().step_3(), element_hover: neutral().dark().step_4(), element_active: neutral().dark().step_5(), element_selected: neutral().dark().step_5(), element_disabled: neutral().dark_alpha().step_3(), element_placeholder: neutral().dark().step_11(), element_drop_target: blue().dark_alpha().step_2(), - ghost_element: system.transparent, + ghost_element_background: system.transparent, ghost_element_hover: neutral().dark().step_4(), ghost_element_active: neutral().dark().step_5(), ghost_element_selected: neutral().dark().step_5(), @@ -280,15 +297,32 @@ impl ThemeColors { icon_disabled: neutral().dark().step_9(), icon_placeholder: neutral().dark().step_10(), icon_accent: blue().dark().step_11(), - status_bar: neutral().dark().step_2(), - title_bar: neutral().dark().step_2(), - toolbar: neutral().dark().step_1(), - tab_bar: neutral().dark().step_2(), - tab_active: neutral().dark().step_1(), - tab_inactive: neutral().dark().step_2(), - editor: neutral().dark().step_1(), - editor_subheader: neutral().dark().step_2(), + status_bar_background: neutral().dark().step_2(), + title_bar_background: neutral().dark().step_2(), + toolbar_background: neutral().dark().step_1(), + tab_bar_background: neutral().dark().step_2(), + tab_active_background: neutral().dark().step_1(), + tab_inactive_background: neutral().dark().step_2(), + editor_background: neutral().dark().step_1(), + editor_subheader_background: neutral().dark().step_2(), editor_active_line: neutral().dark_alpha().step_3(), + terminal_background: neutral().dark().step_1(), + terminal_ansi_black: black().dark().step_12(), + terminal_ansi_red: red().dark().step_11(), + terminal_ansi_green: green().dark().step_11(), + terminal_ansi_yellow: yellow().dark().step_11(), + terminal_ansi_blue: blue().dark().step_11(), + terminal_ansi_magenta: violet().dark().step_11(), + terminal_ansi_cyan: cyan().dark().step_11(), + terminal_ansi_white: neutral().dark().step_12(), + terminal_ansi_bright_black: black().dark().step_11(), + terminal_ansi_bright_red: red().dark().step_10(), + terminal_ansi_bright_green: green().dark().step_10(), + terminal_ansi_bright_yellow: yellow().dark().step_10(), + terminal_ansi_bright_blue: blue().dark().step_10(), + terminal_ansi_bright_magenta: violet().dark().step_10(), + terminal_ansi_bright_cyan: cyan().dark().step_10(), + terminal_ansi_bright_white: neutral().dark().step_11(), } } } diff --git a/crates/theme2/src/theme2.rs b/crates/theme2/src/theme2.rs index faf252e2e5d071b700d7f672cafa17a04e60f0cd..b8e22f8319a523e123c15915a5990fdf69ac6121 100644 --- a/crates/theme2/src/theme2.rs +++ b/crates/theme2/src/theme2.rs @@ -17,7 +17,7 @@ pub use syntax::*; use gpui::{AppContext, Hsla, SharedString}; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, PartialEq, Clone, Copy)] pub enum Appearance { Light, Dark, diff --git a/crates/theme2/src/themes/.gitkeep b/crates/theme2/src/themes/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/crates/ui2/src/components/button.rs b/crates/ui2/src/components/button.rs index 381db20a8336ccf02694537f3760d5e10a23989a..c13460aadd92645b449c53f4d15c4c225b7d3083 100644 --- a/crates/ui2/src/components/button.rs +++ b/crates/ui2/src/components/button.rs @@ -41,8 +41,8 @@ pub enum ButtonVariant { impl ButtonVariant { pub fn bg_color(&self, cx: &mut WindowContext) -> Hsla { match self { - ButtonVariant::Ghost => cx.theme().colors().ghost_element, - ButtonVariant::Filled => cx.theme().colors().element, + ButtonVariant::Ghost => cx.theme().colors().ghost_element_background, + ButtonVariant::Filled => cx.theme().colors().element_background, } } diff --git a/crates/ui2/src/components/checkbox.rs b/crates/ui2/src/components/checkbox.rs index 3add6cebaccc07847310ce1445dc6ecf0a6f635b..4b6a6240bbe057ba59ee47460d1a00888f42e9be 100644 --- a/crates/ui2/src/components/checkbox.rs +++ b/crates/ui2/src/components/checkbox.rs @@ -120,7 +120,10 @@ impl Checkbox { cx.theme().colors().element_selected, cx.theme().colors().border, ), - (false, false) => (cx.theme().colors().element, cx.theme().colors().border), + (false, false) => ( + cx.theme().colors().element_background, + cx.theme().colors().border, + ), }; div() diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 4f265a376dec5847e89be537064a843515607341..87be445c1990c486345d96263976080b1d96b157 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -46,7 +46,7 @@ impl ContextMenu { fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { v_stack() .flex() - .bg(cx.theme().colors().elevated_surface) + .bg(cx.theme().colors().elevated_surface_background) .border() .border_color(cx.theme().colors().border) .child(List::new( diff --git a/crates/ui2/src/components/icon_button.rs b/crates/ui2/src/components/icon_button.rs index 101c845a76ed490e051bb02416c1f4bd05b4c1a5..8fe1a1fa9bc37d08002ed07e07bb167e05a2bd2e 100644 --- a/crates/ui2/src/components/icon_button.rs +++ b/crates/ui2/src/components/icon_button.rs @@ -73,12 +73,12 @@ impl IconButton { let (bg_color, bg_hover_color, bg_active_color) = match self.variant { ButtonVariant::Filled => ( - cx.theme().colors().element, + cx.theme().colors().element_background, cx.theme().colors().element_hover, cx.theme().colors().element_active, ), ButtonVariant::Ghost => ( - cx.theme().colors().ghost_element, + cx.theme().colors().ghost_element_background, cx.theme().colors().ghost_element_hover, cx.theme().colors().ghost_element_active, ), diff --git a/crates/ui2/src/components/indicator.rs b/crates/ui2/src/components/indicator.rs index 1f6e00e621ad02132f85540db985a1a2abd40c31..94398ab7f6016640d55e20a69d8e6939ca75c51a 100644 --- a/crates/ui2/src/components/indicator.rs +++ b/crates/ui2/src/components/indicator.rs @@ -14,7 +14,7 @@ impl UnreadIndicator { div() .rounded_full() .border_2() - .border_color(cx.theme().colors().surface) + .border_color(cx.theme().colors().surface_background) .w(px(9.0)) .h(px(9.0)) .z_index(2) diff --git a/crates/ui2/src/components/input.rs b/crates/ui2/src/components/input.rs index 2884470ce21193085e165cc1b0b92fb710c585a0..f288f3ca563d861bfb9b17e38d9ea7b9a2bea40a 100644 --- a/crates/ui2/src/components/input.rs +++ b/crates/ui2/src/components/input.rs @@ -59,12 +59,12 @@ impl Input { fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { let (input_bg, input_hover_bg, input_active_bg) = match self.variant { InputVariant::Ghost => ( - cx.theme().colors().ghost_element, + cx.theme().colors().ghost_element_background, cx.theme().colors().ghost_element_hover, cx.theme().colors().ghost_element_active, ), InputVariant::Filled => ( - cx.theme().colors().element, + cx.theme().colors().element_background, cx.theme().colors().element_hover, cx.theme().colors().element_active, ), diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index 88cabbdc88bbd45fffb34d14682a3e8d546a68bc..8b8fba8c08d2da0ab097a82adc0a852925f1c30f 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -66,7 +66,7 @@ impl Key { .rounded_md() .text_sm() .text_color(cx.theme().colors().text) - .bg(cx.theme().colors().element) + .bg(cx.theme().colors().element_background) .child(self.key.clone()) } } diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index 543432a8935a5392e96e5e1a8ca074adf5388d54..b30beacd9837af2bf6fa83e5810425cde600c010 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -79,7 +79,7 @@ impl ListHeader { h_stack() .w_full() - .bg(cx.theme().colors().surface) + .bg(cx.theme().colors().surface_background) // TODO: Add focus state // .when(self.state == InteractionState::Focused, |this| { // this.border() @@ -307,7 +307,7 @@ impl ListEntry { div() .relative() .group("") - .bg(cx.theme().colors().surface) + .bg(cx.theme().colors().surface_background) // TODO: Add focus state .child( sized_item diff --git a/crates/ui2/src/components/notification_toast.rs b/crates/ui2/src/components/notification_toast.rs index 59078c98f43d2a079c5de75b428eae1073c8803e..e8739b925c7e03c2a4fb2eb77cf005ea72ec665e 100644 --- a/crates/ui2/src/components/notification_toast.rs +++ b/crates/ui2/src/components/notification_toast.rs @@ -34,7 +34,7 @@ impl NotificationToast { .px_1p5() .rounded_lg() .shadow_md() - .bg(cx.theme().colors().elevated_surface) + .bg(cx.theme().colors().elevated_surface_background) .child(div().size_full().child(self.label.clone())) } } diff --git a/crates/ui2/src/components/palette.rs b/crates/ui2/src/components/palette.rs index a1f3eb7e1c4a9f044ac6a4b810643a044fc578b4..269b39d86d5bc4fbbfa34fa20f9418a335b47641 100644 --- a/crates/ui2/src/components/palette.rs +++ b/crates/ui2/src/components/palette.rs @@ -47,7 +47,7 @@ impl Palette { .id(self.id.clone()) .w_96() .rounded_lg() - .bg(cx.theme().colors().elevated_surface) + .bg(cx.theme().colors().elevated_surface_background) .border() .border_color(cx.theme().colors().border) .child( @@ -56,7 +56,12 @@ impl Palette { .child(v_stack().py_0p5().px_1().child(div().px_2().py_0p5().child( Label::new(self.input_placeholder.clone()).color(LabelColor::Placeholder), ))) - .child(div().h_px().w_full().bg(cx.theme().colors().element)) + .child( + div() + .h_px() + .w_full() + .bg(cx.theme().colors().element_background), + ) .child( v_stack() .id("items") diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index 5d941eb50ea3e7c8084b73c7792a2b6dcd0c378a..ba88abb337259e2e56d1b9b5e1eabb169fc0827c 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -107,7 +107,7 @@ impl Panel { PanelSide::Right => this.border_l(), PanelSide::Bottom => this.border_b().w_full().h(current_size), }) - .bg(cx.theme().colors().surface) + .bg(cx.theme().colors().surface_background) .border_color(cx.theme().colors().border) .children(self.children) } diff --git a/crates/ui2/src/components/tab.rs b/crates/ui2/src/components/tab.rs index e8b0ee3be59b19fd8307f3485971b2fafb2a89f4..47de0541f1d6287a0e800c298e45c76486c3ef57 100644 --- a/crates/ui2/src/components/tab.rs +++ b/crates/ui2/src/components/tab.rs @@ -109,12 +109,12 @@ impl Tab { let (tab_bg, tab_hover_bg, tab_active_bg) = match self.current { false => ( - cx.theme().colors().tab_inactive, + cx.theme().colors().tab_inactive_background, cx.theme().colors().ghost_element_hover, cx.theme().colors().ghost_element_active, ), true => ( - cx.theme().colors().tab_active, + cx.theme().colors().tab_active_background, cx.theme().colors().element_hover, cx.theme().colors().element_active, ), diff --git a/crates/ui2/src/components/toast.rs b/crates/ui2/src/components/toast.rs index 3b81ac42b44abf45fac20337b8f1392d9d529941..4ab6625dbaed89311a78227610b27434f91f7925 100644 --- a/crates/ui2/src/components/toast.rs +++ b/crates/ui2/src/components/toast.rs @@ -54,7 +54,7 @@ impl Toast { .rounded_lg() .shadow_md() .overflow_hidden() - .bg(cx.theme().colors().elevated_surface) + .bg(cx.theme().colors().elevated_surface_background) .children(self.children) } } diff --git a/crates/ui2/src/to_extract/buffer.rs b/crates/ui2/src/to_extract/buffer.rs index 2b3db676ce795dac12a930f1ad48b8c3724751af..e12beff2fce5e8c8d081c44e832c3a19465e7b3f 100644 --- a/crates/ui2/src/to_extract/buffer.rs +++ b/crates/ui2/src/to_extract/buffer.rs @@ -220,7 +220,7 @@ impl Buffer { .flex_1() .w_full() .h_full() - .bg(cx.theme().colors().editor) + .bg(cx.theme().colors().editor_background) .children(rows) } } diff --git a/crates/ui2/src/to_extract/buffer_search.rs b/crates/ui2/src/to_extract/buffer_search.rs index 5d7de1b408a90159269fc7edc11d634a62c607d8..02f689ca3e009bca7dbedc6fc015b185321e8f90 100644 --- a/crates/ui2/src/to_extract/buffer_search.rs +++ b/crates/ui2/src/to_extract/buffer_search.rs @@ -30,14 +30,17 @@ impl Render for BufferSearch { type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Div { - h_stack().bg(cx.theme().colors().toolbar).p_2().child( - h_stack().child(Input::new("Search")).child( - IconButton::::new("replace", Icon::Replace) - .when(self.is_replace_open, |this| this.color(IconColor::Accent)) - .on_click(|buffer_search, cx| { - buffer_search.toggle_replace(cx); - }), - ), - ) + h_stack() + .bg(cx.theme().colors().toolbar_background) + .p_2() + .child( + h_stack().child(Input::new("Search")).child( + IconButton::::new("replace", Icon::Replace) + .when(self.is_replace_open, |this| this.color(IconColor::Accent)) + .on_click(|buffer_search, cx| { + buffer_search.toggle_replace(cx); + }), + ), + ) } } diff --git a/crates/ui2/src/to_extract/collab_panel.rs b/crates/ui2/src/to_extract/collab_panel.rs index 9019456dd131800efecbd68ac1d8bcabae704090..9d9dc861e2a1c2ce073040334e6ccaaf5ab2562e 100644 --- a/crates/ui2/src/to_extract/collab_panel.rs +++ b/crates/ui2/src/to_extract/collab_panel.rs @@ -17,7 +17,7 @@ impl CollabPanel { v_stack() .id(self.id.clone()) .h_full() - .bg(cx.theme().colors().surface) + .bg(cx.theme().colors().surface_background) .child( v_stack() .id("crdb") diff --git a/crates/ui2/src/to_extract/multi_buffer.rs b/crates/ui2/src/to_extract/multi_buffer.rs index ea130f20bd447a2e31ea3f6e04e3e2ff08470dae..1334703015b1373255ba5113bcce143ee790413b 100644 --- a/crates/ui2/src/to_extract/multi_buffer.rs +++ b/crates/ui2/src/to_extract/multi_buffer.rs @@ -24,7 +24,7 @@ impl MultiBuffer { .items_center() .justify_between() .p_4() - .bg(cx.theme().colors().editor_subheader) + .bg(cx.theme().colors().editor_subheader_background) .child(Label::new("main.rs")) .child(IconButton::new("arrow_up_right", Icon::ArrowUpRight)), ) diff --git a/crates/ui2/src/to_extract/notifications_panel.rs b/crates/ui2/src/to_extract/notifications_panel.rs index 789aa2b0aa11d5f2dded289e1d99ddc433cfae2f..84794b71b21993cf1c41e9e15d8d388c39d5a140 100644 --- a/crates/ui2/src/to_extract/notifications_panel.rs +++ b/crates/ui2/src/to_extract/notifications_panel.rs @@ -22,7 +22,7 @@ impl NotificationsPanel { .flex() .flex_col() .size_full() - .bg(cx.theme().colors().surface) + .bg(cx.theme().colors().surface_background) .child( ListHeader::new("Notifications").meta(Some(ListHeaderMeta::Tools(vec![ Icon::AtSign, @@ -43,7 +43,7 @@ impl NotificationsPanel { .p_1() // TODO: Add cursor style // .cursor(Cursor::IBeam) - .bg(cx.theme().colors().element) + .bg(cx.theme().colors().element_background) .border() .border_color(cx.theme().colors().border_variant) .child( diff --git a/crates/ui2/src/to_extract/panes.rs b/crates/ui2/src/to_extract/panes.rs index bf0f27d43f32742abfe61c527c67dd6d8fd0f96a..a1e040b0cad9a5365548feb150f1084f4fa3404e 100644 --- a/crates/ui2/src/to_extract/panes.rs +++ b/crates/ui2/src/to_extract/panes.rs @@ -113,7 +113,7 @@ impl PaneGroup { .gap_px() .w_full() .h_full() - .bg(cx.theme().colors().editor) + .bg(cx.theme().colors().editor_background) .children(self.groups.into_iter().map(|group| group.render(view, cx))); if self.split_direction == SplitDirection::Horizontal { diff --git a/crates/ui2/src/to_extract/project_panel.rs b/crates/ui2/src/to_extract/project_panel.rs index 807768427b21729f1b1bfd6f3cc107cddb67423d..a34a30bcbcf0ae71a19caff2884039933d1bcce4 100644 --- a/crates/ui2/src/to_extract/project_panel.rs +++ b/crates/ui2/src/to_extract/project_panel.rs @@ -19,7 +19,7 @@ impl ProjectPanel { .flex() .flex_col() .size_full() - .bg(cx.theme().colors().surface) + .bg(cx.theme().colors().surface_background) .child( div() .id("project-panel-contents") diff --git a/crates/ui2/src/to_extract/status_bar.rs b/crates/ui2/src/to_extract/status_bar.rs index 136472f605abc71600137ef567e43d45c8129e45..34a5993e69da552d9045a7ab23c5fa30d3d218e3 100644 --- a/crates/ui2/src/to_extract/status_bar.rs +++ b/crates/ui2/src/to_extract/status_bar.rs @@ -93,7 +93,7 @@ impl StatusBar { .items_center() .justify_between() .w_full() - .bg(cx.theme().colors().status_bar) + .bg(cx.theme().colors().status_bar_background) .child(self.left_tools(view, cx)) .child(self.right_tools(view, cx)) } diff --git a/crates/ui2/src/to_extract/tab_bar.rs b/crates/ui2/src/to_extract/tab_bar.rs index bb7fca11534dbcb5981a0d695ffb3962ebe67e6c..a1280441832f1a6a8caee0c1a63ec989d021ad37 100644 --- a/crates/ui2/src/to_extract/tab_bar.rs +++ b/crates/ui2/src/to_extract/tab_bar.rs @@ -31,7 +31,7 @@ impl TabBar { .id(self.id.clone()) .w_full() .flex() - .bg(cx.theme().colors().tab_bar) + .bg(cx.theme().colors().tab_bar_background) // Left Side .child( div() diff --git a/crates/ui2/src/to_extract/terminal.rs b/crates/ui2/src/to_extract/terminal.rs index 051ebf7315400298f6b22eb8ae5adb108a7098fe..b912a5960768e3b17a11988560a0201ac6ee2902 100644 --- a/crates/ui2/src/to_extract/terminal.rs +++ b/crates/ui2/src/to_extract/terminal.rs @@ -24,7 +24,7 @@ impl Terminal { div() .w_full() .flex() - .bg(cx.theme().colors().surface) + .bg(cx.theme().colors().surface_background) .child( div().px_1().flex().flex_none().gap_2().child( div() diff --git a/crates/ui2/src/to_extract/toolbar.rs b/crates/ui2/src/to_extract/toolbar.rs index 05a5c991d69d645602f2966f270124efcb5209bd..0e3e7c259ff971622feb5b89fbeddc3bf5023a2f 100644 --- a/crates/ui2/src/to_extract/toolbar.rs +++ b/crates/ui2/src/to_extract/toolbar.rs @@ -56,7 +56,7 @@ impl Toolbar { fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { div() - .bg(cx.theme().colors().toolbar) + .bg(cx.theme().colors().toolbar_background) .p_2() .flex() .justify_between() diff --git a/crates/ui2/src/to_extract/traffic_lights.rs b/crates/ui2/src/to_extract/traffic_lights.rs index 9080276cdd281888813f06c34fee8a256e540aa8..677fae886c838c03cc42ed300ce9df4f79d1d883 100644 --- a/crates/ui2/src/to_extract/traffic_lights.rs +++ b/crates/ui2/src/to_extract/traffic_lights.rs @@ -28,7 +28,7 @@ impl TrafficLight { (true, TrafficLightColor::Red) => system_colors.mac_os_traffic_light_red, (true, TrafficLightColor::Yellow) => system_colors.mac_os_traffic_light_yellow, (true, TrafficLightColor::Green) => system_colors.mac_os_traffic_light_green, - (false, _) => cx.theme().colors().element, + (false, _) => cx.theme().colors().element_background, }; div().w_3().h_3().rounded_full().bg(fill) diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index acc41deba880ed986e1391d6fb61d4818ffeef5a..44f705ebb2a734f03e238312df08be54d7bd7368 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -1363,12 +1363,12 @@ impl Pane { let (tab_bg, tab_hover_bg, tab_active_bg) = match ix == self.active_item_index { false => ( - cx.theme().colors().tab_inactive, + cx.theme().colors().tab_inactive_background, cx.theme().colors().ghost_element_hover, cx.theme().colors().ghost_element_active, ), true => ( - cx.theme().colors().tab_active, + cx.theme().colors().tab_active_background, cx.theme().colors().element_hover, cx.theme().colors().element_active, ), @@ -1432,7 +1432,7 @@ impl Pane { .id("tab_bar") .w_full() .flex() - .bg(cx.theme().colors().tab_bar) + .bg(cx.theme().colors().tab_bar_background) // Left Side .child( div() diff --git a/crates/workspace2/src/status_bar.rs b/crates/workspace2/src/status_bar.rs index ca4ebcdb1305bf72b6d04d1409d4c80358ecbab0..ac99be9f892c84c1226d5fbfec70e1a3afa79ea2 100644 --- a/crates/workspace2/src/status_bar.rs +++ b/crates/workspace2/src/status_bar.rs @@ -44,7 +44,7 @@ impl Render for StatusBar { .items_center() .justify_between() .w_full() - .bg(cx.theme().colors().status_bar) + .bg(cx.theme().colors().status_bar_background) .child(self.render_left_tools(cx)) .child(self.render_right_tools(cx)) } diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 6e4c9e6cfd8d5148f5ccc37d42a7d4369b643524..7561c903d3bf05c5664632015c80350a8f897626 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -2697,7 +2697,7 @@ impl Workspace { fn render_titlebar(&self, cx: &mut ViewContext) -> impl Component { div() - .bg(cx.theme().colors().title_bar) + .bg(cx.theme().colors().title_bar_background) .when( !matches!(cx.window_bounds(), WindowBounds::Fullscreen), |s| s.pl_20(), From bfb860c06c7f5d1aa1db9e5596fab14c6f0e44cf Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 6 Nov 2023 19:29:31 +0200 Subject: [PATCH 29/32] Properly toggle diagnostics --- crates/diagnostics/src/diagnostics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 1ec4105fbdaf9c02fbadea88c02263c953795371..e794771434a0981fe5af2efa1ae19d9db7b0f523 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -227,6 +227,7 @@ impl ProjectDiagnosticsEditor { fn toggle_warnings(&mut self, _: &ToggleWarnings, cx: &mut ViewContext) { self.include_warnings = !self.include_warnings; + self.paths_to_update = self.current_diagnostics.clone(); self.update_excerpts(None, cx); cx.notify(); } From d88dccffbc035178e8437204f9e41d23c3c04485 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 6 Nov 2023 11:02:30 -0700 Subject: [PATCH 30/32] Allow multiple subscriptions from one entity handle --- crates/gpui2/src/subscription.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gpui2/src/subscription.rs b/crates/gpui2/src/subscription.rs index 744e83bbbddda1a6e6264fa62f81fb23c30f6830..2f4ec0d2f13212440fe7d23585781bac7b2be069 100644 --- a/crates/gpui2/src/subscription.rs +++ b/crates/gpui2/src/subscription.rs @@ -38,7 +38,7 @@ where lock.subscribers .entry(emitter_key.clone()) .or_default() - .insert(Default::default()) + .get_or_insert_with(|| Default::default()) .insert(subscriber_id, callback); let this = self.0.clone(); Subscription { From d224f511fabbe9db12023bdf97a3cf3d4a148d3b Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Mon, 6 Nov 2023 19:22:25 +0100 Subject: [PATCH 31/32] Add interactivity to `Checkbox` component (#3240) This PR adds interactivity to the `Checkbox` component. They can now be checked and unchecked by clicking them. Release Notes: - N/A --- crates/gpui2/src/element.rs | 13 +++ crates/ui2/src/components/button.rs | 2 +- crates/ui2/src/components/checkbox.rs | 113 +++++++++++++------------ crates/ui2/src/prelude.rs | 11 ++- crates/ui2/src/to_extract/workspace.rs | 23 ++++- 5 files changed, 106 insertions(+), 56 deletions(-) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index a92dbd6ff94a98165f5b200bc4eadedb2471bf5a..2a0f557272f4899eb21f2bbb3123a08045a56158 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -212,6 +212,19 @@ pub trait Component { { self.map(|this| if condition { then(this) } else { this }) } + + fn when_some(self, option: Option, then: impl FnOnce(Self, T) -> Self) -> Self + where + Self: Sized, + { + self.map(|this| { + if let Some(value) = option { + then(this, value) + } else { + this + } + }) + } } impl Component for AnyElement { diff --git a/crates/ui2/src/components/button.rs b/crates/ui2/src/components/button.rs index c13460aadd92645b449c53f4d15c4c225b7d3083..178813dd5fc424715af72ebbf35c9fb535af21ed 100644 --- a/crates/ui2/src/components/button.rs +++ b/crates/ui2/src/components/button.rs @@ -61,7 +61,7 @@ impl ButtonVariant { } } -pub type ClickHandler = Arc) + Send + Sync>; +pub type ClickHandler = Arc) + Send + Sync>; struct ButtonHandlers { click: Option>, diff --git a/crates/ui2/src/components/checkbox.rs b/crates/ui2/src/components/checkbox.rs index 4b6a6240bbe057ba59ee47460d1a00888f42e9be..9632a6681066f06e35bebfb834dd78ab9b983929 100644 --- a/crates/ui2/src/components/checkbox.rs +++ b/crates/ui2/src/components/checkbox.rs @@ -1,63 +1,58 @@ -///! # Checkbox -///! -///! Checkboxes are used for multiple choices, not for mutually exclusive choices. -///! Each checkbox works independently from other checkboxes in the list, -///! therefore checking an additional box does not affect any other selections. +use std::sync::Arc; + use gpui2::{ - div, Component, ParentElement, SharedString, StatelessInteractive, Styled, ViewContext, + div, Component, ElementId, ParentElement, StatefulInteractive, StatelessInteractive, Styled, + ViewContext, }; use theme2::ActiveTheme; -use crate::{Icon, IconColor, IconElement, Selected}; +use crate::{Icon, IconColor, IconElement, Selection}; + +pub type CheckHandler = Arc) + Send + Sync>; +/// # Checkbox +/// +/// Checkboxes are used for multiple choices, not for mutually exclusive choices. +/// Each checkbox works independently from other checkboxes in the list, +/// therefore checking an additional box does not affect any other selections. #[derive(Component)] -pub struct Checkbox { - id: SharedString, - checked: Selected, +pub struct Checkbox { + id: ElementId, + checked: Selection, disabled: bool, + on_click: Option>, } -impl Checkbox { - pub fn new(id: impl Into) -> Self { +impl Checkbox { + pub fn new(id: impl Into, checked: Selection) -> Self { Self { id: id.into(), - checked: Selected::Unselected, + checked, disabled: false, + on_click: None, } } - pub fn toggle(mut self) -> Self { - self.checked = match self.checked { - Selected::Selected => Selected::Unselected, - Selected::Unselected => Selected::Selected, - Selected::Indeterminate => Selected::Selected, - }; + pub fn disabled(mut self, disabled: bool) -> Self { + self.disabled = disabled; self } - pub fn set_indeterminate(mut self) -> Self { - self.checked = Selected::Indeterminate; + pub fn on_click( + mut self, + handler: impl 'static + Fn(Selection, &mut V, &mut ViewContext) + Send + Sync, + ) -> Self { + self.on_click = Some(Arc::new(handler)); self } - pub fn set_disabled(mut self, disabled: bool) -> Self { - self.disabled = disabled; - self - } + pub fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + let group_id = format!("checkbox_group_{:?}", self.id); - pub fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let group_id = format!("checkbox_group_{}", self.id); - - // The icon is different depending on the state of the checkbox. - // - // We need the match to return all the same type, - // so we wrap the eatch result in a div. - // - // We are still exploring the best way to handle this. let icon = match self.checked { // When selected, we show a checkmark. - Selected::Selected => { - div().child( + Selection::Selected => { + Some( IconElement::new(Icon::Check) .size(crate::IconSize::Small) .color( @@ -71,8 +66,8 @@ impl Checkbox { ) } // In an indeterminate state, we show a dash. - Selected::Indeterminate => { - div().child( + Selection::Indeterminate => { + Some( IconElement::new(Icon::Dash) .size(crate::IconSize::Small) .color( @@ -86,7 +81,7 @@ impl Checkbox { ) } // When unselected, we show nothing. - Selected::Unselected => div(), + Selection::Unselected => None, }; // A checkbox could be in an indeterminate state, @@ -98,7 +93,7 @@ impl Checkbox { // For the sake of styles we treat the indeterminate state as selected, // but it's icon will be different. let selected = - self.checked == Selected::Selected || self.checked == Selected::Indeterminate; + self.checked == Selection::Selected || self.checked == Selection::Indeterminate; // We could use something like this to make the checkbox background when selected: // @@ -127,6 +122,7 @@ impl Checkbox { }; div() + .id(self.id) // Rather than adding `px_1()` to add some space around the checkbox, // we use a larger parent element to create a slightly larger // click area for the checkbox. @@ -161,7 +157,13 @@ impl Checkbox { el.bg(cx.theme().colors().element_hover) }) }) - .child(icon), + .children(icon), + ) + .when_some( + self.on_click.filter(|_| !self.disabled), + |this, on_click| { + this.on_click(move |view, _, cx| on_click(self.checked.inverse(), view, cx)) + }, ) } } @@ -182,7 +184,7 @@ mod stories { fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) - .child(Story::title_for::<_, Checkbox>(cx)) + .child(Story::title_for::<_, Checkbox>(cx)) .child(Story::label(cx, "Default")) .child( h_stack() @@ -191,9 +193,12 @@ mod stories { .rounded_md() .border() .border_color(cx.theme().colors().border) - .child(Checkbox::new("checkbox-enabled")) - .child(Checkbox::new("checkbox-intermediate").set_indeterminate()) - .child(Checkbox::new("checkbox-selected").toggle()), + .child(Checkbox::new("checkbox-enabled", Selection::Unselected)) + .child(Checkbox::new( + "checkbox-intermediate", + Selection::Indeterminate, + )) + .child(Checkbox::new("checkbox-selected", Selection::Selected)), ) .child(Story::label(cx, "Disabled")) .child( @@ -203,16 +208,20 @@ mod stories { .rounded_md() .border() .border_color(cx.theme().colors().border) - .child(Checkbox::new("checkbox-disabled").set_disabled(true)) .child( - Checkbox::new("checkbox-disabled-intermediate") - .set_disabled(true) - .set_indeterminate(), + Checkbox::new("checkbox-disabled", Selection::Unselected) + .disabled(true), + ) + .child( + Checkbox::new( + "checkbox-disabled-intermediate", + Selection::Indeterminate, + ) + .disabled(true), ) .child( - Checkbox::new("checkbox-disabled-selected") - .set_disabled(true) - .toggle(), + Checkbox::new("checkbox-disabled-selected", Selection::Selected) + .disabled(true), ), ) } diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index 072ed0006052c402b58b422e918442829f7d8b88..134b293d3daa0a5b14f5d3916e0ae44f77f291a3 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -155,9 +155,18 @@ impl InteractionState { } #[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)] -pub enum Selected { +pub enum Selection { #[default] Unselected, Indeterminate, Selected, } + +impl Selection { + pub fn inverse(&self) -> Self { + match self { + Self::Unselected | Self::Indeterminate => Self::Selected, + Self::Selected => Self::Unselected, + } + } +} diff --git a/crates/ui2/src/to_extract/workspace.rs b/crates/ui2/src/to_extract/workspace.rs index 97570a33e3b83d8856db49eed178d53677eb7b48..77b9bc45393db4d905be3c3c08c8c2b18150f4e8 100644 --- a/crates/ui2/src/to_extract/workspace.rs +++ b/crates/ui2/src/to_extract/workspace.rs @@ -7,8 +7,8 @@ use theme2::ThemeSettings; use crate::prelude::*; use crate::{ - static_livestream, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel, CollabPanel, - EditorPane, Label, LanguageSelector, NotificationsPanel, Pane, PaneGroup, Panel, + static_livestream, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel, Checkbox, + CollabPanel, EditorPane, Label, LanguageSelector, NotificationsPanel, Pane, PaneGroup, Panel, PanelAllowedSides, PanelSide, ProjectPanel, SplitDirection, StatusBar, Terminal, TitleBar, Toast, ToastOrigin, }; @@ -42,6 +42,7 @@ pub struct Workspace { show_terminal: bool, show_debug: bool, show_language_selector: bool, + test_checkbox_selection: Selection, debug: Gpui2UiDebug, } @@ -58,6 +59,7 @@ impl Workspace { show_language_selector: false, show_debug: false, show_notifications_panel: true, + test_checkbox_selection: Selection::Unselected, debug: Gpui2UiDebug::default(), } } @@ -217,6 +219,23 @@ impl Render for Workspace { .text_color(cx.theme().colors().text) .bg(cx.theme().colors().background) .child(self.title_bar.clone()) + .child( + div() + .absolute() + .top_12() + .left_12() + .z_index(99) + .bg(cx.theme().colors().background) + .child( + Checkbox::new("test_checkbox", self.test_checkbox_selection).on_click( + |selection, workspace: &mut Workspace, cx| { + workspace.test_checkbox_selection = selection; + + cx.notify(); + }, + ), + ), + ) .child( div() .flex_1() From 496518f3e8f8b1be75e7367e3b80ba4ce774496c Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 6 Nov 2023 11:46:10 -0700 Subject: [PATCH 32/32] Use gpui instead of gpui2 consistenytly --- crates/gpui2/src/styled.rs | 2 +- crates/gpui2_macros/src/derive_component.rs | 6 +++--- crates/gpui2_macros/src/style_helpers.rs | 4 ++-- crates/live_kit_client2/Cargo.toml | 6 +++--- crates/live_kit_client2/examples/test_app.rs | 6 +++--- crates/live_kit_client2/src/test.rs | 2 +- crates/storybook2/Cargo.toml | 4 ++-- crates/storybook2/src/assets.rs | 2 +- crates/storybook2/src/stories/colors.rs | 4 ++-- crates/storybook2/src/stories/focus.rs | 4 ++-- crates/storybook2/src/stories/kitchen_sink.rs | 2 +- crates/storybook2/src/stories/scroll.rs | 4 ++-- crates/storybook2/src/stories/text.rs | 4 ++-- crates/storybook2/src/stories/z_index.rs | 2 +- crates/storybook2/src/story_selector.rs | 2 +- crates/storybook2/src/storybook2.rs | 8 ++++---- crates/terminal2/src/mappings/colors.rs | 2 +- crates/ui2/Cargo.toml | 2 +- crates/ui2/docs/hello-world.md | 10 +++++----- crates/ui2/src/components/avatar.rs | 6 +++--- crates/ui2/src/components/button.rs | 4 ++-- crates/ui2/src/components/checkbox.rs | 4 ++-- crates/ui2/src/components/context_menu.rs | 2 +- crates/ui2/src/components/details.rs | 2 +- crates/ui2/src/components/facepile.rs | 2 +- crates/ui2/src/components/icon.rs | 4 ++-- crates/ui2/src/components/icon_button.rs | 2 +- crates/ui2/src/components/indicator.rs | 2 +- crates/ui2/src/components/input.rs | 2 +- crates/ui2/src/components/keybinding.rs | 2 +- crates/ui2/src/components/label.rs | 4 ++-- crates/ui2/src/components/list.rs | 2 +- crates/ui2/src/components/modal.rs | 2 +- crates/ui2/src/components/notification_toast.rs | 2 +- crates/ui2/src/components/palette.rs | 4 ++-- crates/ui2/src/components/panel.rs | 4 ++-- crates/ui2/src/components/player.rs | 2 +- crates/ui2/src/components/slot.rs | 2 +- crates/ui2/src/components/stack.rs | 2 +- crates/ui2/src/components/tab.rs | 2 +- crates/ui2/src/components/toast.rs | 4 ++-- crates/ui2/src/components/toggle.rs | 2 +- crates/ui2/src/components/tooltip.rs | 2 +- crates/ui2/src/prelude.rs | 4 ++-- crates/ui2/src/settings.rs | 2 +- crates/ui2/src/static_data.rs | 2 +- crates/ui2/src/story.rs | 2 +- crates/ui2/src/to_extract/assistant_panel.rs | 4 ++-- crates/ui2/src/to_extract/breadcrumb.rs | 4 ++-- crates/ui2/src/to_extract/buffer.rs | 4 ++-- crates/ui2/src/to_extract/buffer_search.rs | 2 +- crates/ui2/src/to_extract/chat_panel.rs | 2 +- crates/ui2/src/to_extract/collab_panel.rs | 2 +- crates/ui2/src/to_extract/command_palette.rs | 2 +- crates/ui2/src/to_extract/copilot.rs | 2 +- crates/ui2/src/to_extract/editor_pane.rs | 2 +- crates/ui2/src/to_extract/language_selector.rs | 2 +- crates/ui2/src/to_extract/multi_buffer.rs | 2 +- crates/ui2/src/to_extract/notifications_panel.rs | 4 ++-- crates/ui2/src/to_extract/panes.rs | 2 +- crates/ui2/src/to_extract/project_panel.rs | 4 ++-- crates/ui2/src/to_extract/recent_projects.rs | 2 +- crates/ui2/src/to_extract/tab_bar.rs | 4 ++-- crates/ui2/src/to_extract/terminal.rs | 4 ++-- crates/ui2/src/to_extract/theme_selector.rs | 2 +- crates/ui2/src/to_extract/title_bar.rs | 2 +- crates/ui2/src/to_extract/toolbar.rs | 4 ++-- crates/ui2/src/to_extract/traffic_lights.rs | 2 +- crates/ui2/src/to_extract/workspace.rs | 4 ++-- crates/zed2/src/languages/language_plugin.rs | 2 +- test.rs | 6 +++--- 71 files changed, 111 insertions(+), 111 deletions(-) diff --git a/crates/gpui2/src/styled.rs b/crates/gpui2/src/styled.rs index 4a9a5d7ecf0c1fc18791dd5be596f4bfc488c7b4..a272ab95b14d7416e91d0bf166f2683e7941f02e 100644 --- a/crates/gpui2/src/styled.rs +++ b/crates/gpui2/src/styled.rs @@ -1,5 +1,5 @@ use crate::{ - self as gpui2, hsla, point, px, relative, rems, AlignItems, CursorStyle, DefiniteLength, + self as gpui, hsla, point, px, relative, rems, AlignItems, CursorStyle, DefiniteLength, Display, Fill, FlexDirection, Hsla, JustifyContent, Length, Position, Rems, SharedString, StyleRefinement, Visibility, }; diff --git a/crates/gpui2_macros/src/derive_component.rs b/crates/gpui2_macros/src/derive_component.rs index a9467033101721082fb3c509251489605f945379..aaf814497aa9ac3963d3cef335a04383fc12f335 100644 --- a/crates/gpui2_macros/src/derive_component.rs +++ b/crates/gpui2_macros/src/derive_component.rs @@ -28,9 +28,9 @@ pub fn derive_component(input: TokenStream) -> TokenStream { let (_, ty_generics, _) = ast.generics.split_for_impl(); let expanded = quote! { - impl #impl_generics gpui2::Component<#view_type> for #name #ty_generics #where_clause { - fn render(self) -> gpui2::AnyElement<#view_type> { - (move |view_state: &mut #view_type, cx: &mut gpui2::ViewContext<'_, #view_type>| self.render(view_state, cx)) + impl #impl_generics gpui::Component<#view_type> for #name #ty_generics #where_clause { + fn render(self) -> gpui::AnyElement<#view_type> { + (move |view_state: &mut #view_type, cx: &mut gpui::ViewContext<'_, #view_type>| self.render(view_state, cx)) .render() } } diff --git a/crates/gpui2_macros/src/style_helpers.rs b/crates/gpui2_macros/src/style_helpers.rs index 9e47d85ef1267717eeb77143b75208d3c5940054..57aef03afa55276293d48f610458c5d29ddf9862 100644 --- a/crates/gpui2_macros/src/style_helpers.rs +++ b/crates/gpui2_macros/src/style_helpers.rs @@ -123,7 +123,7 @@ fn generate_predefined_setter( .iter() .map(|field_tokens| { quote! { - style.#field_tokens = Some((#negation_token gpui2::#length_tokens).into()); + style.#field_tokens = Some((#negation_token gpui::#length_tokens).into()); } }) .collect::>(); @@ -163,7 +163,7 @@ fn generate_custom_value_setter( let method = quote! { #[doc = #doc_string] - fn #method_name(mut self, length: impl std::clone::Clone + Into) -> Self where Self: std::marker::Sized { + fn #method_name(mut self, length: impl std::clone::Clone + Into) -> Self where Self: std::marker::Sized { let style = self.style(); #(#field_assignments)* self diff --git a/crates/live_kit_client2/Cargo.toml b/crates/live_kit_client2/Cargo.toml index 5adb71194806c450133e149bc9893e647f3ad74b..b606434b05d2e28171fe42839a7ff17e213028a5 100644 --- a/crates/live_kit_client2/Cargo.toml +++ b/crates/live_kit_client2/Cargo.toml @@ -16,14 +16,14 @@ name = "test_app" test-support = [ "async-trait", "collections/test-support", - "gpui2/test-support", + "gpui/test-support", "live_kit_server", "nanoid", ] [dependencies] collections = { path = "../collections", optional = true } -gpui2 = { package = "gpui2", path = "../gpui2", optional = true } +gpui = { package = "gpui2", path = "../gpui2", optional = true } live_kit_server = { path = "../live_kit_server", optional = true } media = { path = "../media" } @@ -41,7 +41,7 @@ nanoid = { version ="0.4", optional = true} [dev-dependencies] collections = { path = "../collections", features = ["test-support"] } -gpui2 = { package = "gpui2", path = "../gpui2", features = ["test-support"] } +gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] } live_kit_server = { path = "../live_kit_server" } media = { path = "../media" } nanoid = "0.4" diff --git a/crates/live_kit_client2/examples/test_app.rs b/crates/live_kit_client2/examples/test_app.rs index 4062441a06b4e7bede19a3d57dc4835111996b29..98302eb35c049015cbfee131b5dbcf125b7f5956 100644 --- a/crates/live_kit_client2/examples/test_app.rs +++ b/crates/live_kit_client2/examples/test_app.rs @@ -1,7 +1,7 @@ use std::{sync::Arc, time::Duration}; use futures::StreamExt; -use gpui2::KeyBinding; +use gpui::KeyBinding; use live_kit_client2::{ LocalAudioTrack, LocalVideoTrack, RemoteAudioTrackUpdate, RemoteVideoTrackUpdate, Room, }; @@ -16,7 +16,7 @@ struct Quit; fn main() { SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); - gpui2::App::production(Arc::new(())).run(|cx| { + gpui::App::production(Arc::new(())).run(|cx| { #[cfg(any(test, feature = "test-support"))] println!("USING TEST LIVEKIT"); @@ -173,6 +173,6 @@ fn main() { }); } -fn quit(_: &Quit, cx: &mut gpui2::AppContext) { +fn quit(_: &Quit, cx: &mut gpui::AppContext) { cx.quit(); } diff --git a/crates/live_kit_client2/src/test.rs b/crates/live_kit_client2/src/test.rs index 10c97e8d815b1798ed7711cfb33d7dc011635aef..6367e53ba857e979d834c048af06340fa1a8fc89 100644 --- a/crates/live_kit_client2/src/test.rs +++ b/crates/live_kit_client2/src/test.rs @@ -2,7 +2,7 @@ use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use collections::{BTreeMap, HashMap}; use futures::Stream; -use gpui2::BackgroundExecutor; +use gpui::BackgroundExecutor; use live_kit_server::token; use media::core_video::CVImageBuffer; use parking_lot::Mutex; diff --git a/crates/storybook2/Cargo.toml b/crates/storybook2/Cargo.toml index 0f335ae9845e2cdbb370e45c3c201f6dc5ed5ea0..1f3a0b33cc2254671069d8e8c1f0fb0e453db9ae 100644 --- a/crates/storybook2/Cargo.toml +++ b/crates/storybook2/Cargo.toml @@ -14,7 +14,7 @@ anyhow.workspace = true backtrace-on-stack-overflow = "0.3.0" clap = { version = "4.4", features = ["derive", "string"] } chrono = "0.4" -gpui2 = { path = "../gpui2" } +gpui = { package = "gpui2", path = "../gpui2" } itertools = "0.11.0" log.workspace = true rust-embed.workspace = true @@ -29,4 +29,4 @@ ui = { package = "ui2", path = "../ui2", features = ["stories"] } util = { path = "../util" } [dev-dependencies] -gpui2 = { path = "../gpui2", features = ["test-support"] } +gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] } diff --git a/crates/storybook2/src/assets.rs b/crates/storybook2/src/assets.rs index 3d4298454882409b394713a5a899052b4bdda706..9fc71917b45f7fa024a3e157f0a806d6056ef7f4 100644 --- a/crates/storybook2/src/assets.rs +++ b/crates/storybook2/src/assets.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use anyhow::{anyhow, Result}; -use gpui2::{AssetSource, SharedString}; +use gpui::{AssetSource, SharedString}; use rust_embed::RustEmbed; #[derive(RustEmbed)] diff --git a/crates/storybook2/src/stories/colors.rs b/crates/storybook2/src/stories/colors.rs index c1c65d62fa16eca970fe72f286c39c6235d0d46e..13b7b36a8c67c1674f34d54a003a1b6d6788aeb9 100644 --- a/crates/storybook2/src/stories/colors.rs +++ b/crates/storybook2/src/stories/colors.rs @@ -1,5 +1,5 @@ use crate::story::Story; -use gpui2::{px, Div, Render}; +use gpui::{px, Div, Render}; use theme2::{default_color_scales, ColorScaleStep}; use ui::prelude::*; @@ -20,7 +20,7 @@ impl Render for ColorsStory { .flex_col() .gap_1() .overflow_y_scroll() - .text_color(gpui2::white()) + .text_color(gpui::white()) .children(color_scales.into_iter().map(|scale| { div() .flex() diff --git a/crates/storybook2/src/stories/focus.rs b/crates/storybook2/src/stories/focus.rs index aa71040b477abeddee443d851c1eaf1550ec3da1..16c03f87d5421af9d9336e462692102c4cb632bb 100644 --- a/crates/storybook2/src/stories/focus.rs +++ b/crates/storybook2/src/stories/focus.rs @@ -1,4 +1,4 @@ -use gpui2::{ +use gpui::{ div, Div, FocusEnabled, Focusable, KeyBinding, ParentElement, Render, StatefulInteraction, StatelessInteractive, Styled, View, VisualContext, WindowContext, }; @@ -33,7 +33,7 @@ impl FocusStory { impl Render for FocusStory { type Element = Div, FocusEnabled>; - fn render(&mut self, cx: &mut gpui2::ViewContext) -> Self::Element { + fn render(&mut self, cx: &mut gpui::ViewContext) -> Self::Element { let theme = cx.theme(); let color_1 = theme.styles.git.created; let color_2 = theme.styles.git.modified; diff --git a/crates/storybook2/src/stories/kitchen_sink.rs b/crates/storybook2/src/stories/kitchen_sink.rs index cf8277c4f451e0b3e9cf5d9b96781a0ce66d0085..54d6f2a3a967cc3f6e5a29be97e36291c45bdeff 100644 --- a/crates/storybook2/src/stories/kitchen_sink.rs +++ b/crates/storybook2/src/stories/kitchen_sink.rs @@ -1,5 +1,5 @@ use crate::{story::Story, story_selector::ComponentStory}; -use gpui2::{Div, Render, StatefulInteraction, View, VisualContext}; +use gpui::{Div, Render, StatefulInteraction, View, VisualContext}; use strum::IntoEnumIterator; use ui::prelude::*; diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs index 9236629c341e5c1ffa5706e656c0bdbf9bcea09d..cdb48603e093f62e4ef5ee5968af068798e3bce9 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -1,4 +1,4 @@ -use gpui2::{ +use gpui::{ div, px, Component, Div, ParentElement, Render, SharedString, StatefulInteraction, Styled, View, VisualContext, WindowContext, }; @@ -15,7 +15,7 @@ impl ScrollStory { impl Render for ScrollStory { type Element = Div>; - fn render(&mut self, cx: &mut gpui2::ViewContext) -> Self::Element { + fn render(&mut self, cx: &mut gpui::ViewContext) -> Self::Element { let theme = cx.theme(); let color_1 = theme.styles.git.created; let color_2 = theme.styles.git.modified; diff --git a/crates/storybook2/src/stories/text.rs b/crates/storybook2/src/stories/text.rs index 85a9fd51a6ed67860d53e663a31dd30ff18e77ca..b4a4c86e7eed15fb774ea1586e4ab36a1ea5aafe 100644 --- a/crates/storybook2/src/stories/text.rs +++ b/crates/storybook2/src/stories/text.rs @@ -1,4 +1,4 @@ -use gpui2::{div, white, Div, ParentElement, Render, Styled, View, VisualContext, WindowContext}; +use gpui::{div, white, Div, ParentElement, Render, Styled, View, VisualContext, WindowContext}; pub struct TextStory; @@ -11,7 +11,7 @@ impl TextStory { impl Render for TextStory { type Element = Div; - fn render(&mut self, cx: &mut gpui2::ViewContext) -> Self::Element { + fn render(&mut self, cx: &mut gpui::ViewContext) -> Self::Element { div().size_full().bg(white()).child(concat!( "The quick brown fox jumps over the lazy dog. ", "Meanwhile, the lazy dog decided it was time for a change. ", diff --git a/crates/storybook2/src/stories/z_index.rs b/crates/storybook2/src/stories/z_index.rs index c0e1456bc01a1ebb7ffe3f50ccf17ea411315179..46ec0f4a3511ea2b3a3cc7999e203a62d35a01d6 100644 --- a/crates/storybook2/src/stories/z_index.rs +++ b/crates/storybook2/src/stories/z_index.rs @@ -1,4 +1,4 @@ -use gpui2::{px, rgb, Div, Hsla, Render}; +use gpui::{px, rgb, Div, Hsla, Render}; use ui::prelude::*; use crate::story::Story; diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index 2adf2956d33512930bf8e829a3845d7ba5522dbc..f59208ccb8794948dd93afa99155d707ea91ad0d 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -5,7 +5,7 @@ use crate::stories::*; use anyhow::anyhow; use clap::builder::PossibleValue; use clap::ValueEnum; -use gpui2::{AnyView, VisualContext}; +use gpui::{AnyView, VisualContext}; use strum::{EnumIter, EnumString, IntoEnumIterator}; use ui::prelude::*; use ui::{AvatarStory, ButtonStory, DetailsStory, IconStory, InputStory, LabelStory}; diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index 4e2c439db0c723baf4f8d7585281020474eec952..c8849c134278ebe36d583c34a14b6e8961f4885b 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -8,7 +8,7 @@ mod story_selector; use std::sync::Arc; use clap::Parser; -use gpui2::{ +use gpui::{ div, px, size, AnyView, AppContext, Bounds, Div, Render, ViewContext, VisualContext, WindowBounds, WindowOptions, }; @@ -22,7 +22,7 @@ use ui::prelude::*; use crate::assets::Assets; use crate::story_selector::StorySelector; -// gpui2::actions! { +// gpui::actions! { // storybook, // [ToggleInspector] // } @@ -51,7 +51,7 @@ fn main() { let theme_name = args.theme.unwrap_or("Zed Pro Moonlight".to_string()); let asset_source = Arc::new(Assets); - gpui2::App::production(asset_source).run(move |cx| { + gpui::App::production(asset_source).run(move |cx| { load_embedded_fonts(cx).unwrap(); let mut store = SettingsStore::default(); @@ -116,7 +116,7 @@ impl Render for StoryWrapper { } } -fn load_embedded_fonts(cx: &AppContext) -> gpui2::Result<()> { +fn load_embedded_fonts(cx: &AppContext) -> gpui::Result<()> { let font_paths = cx.asset_source().list("fonts")?; let mut embedded_fonts = Vec::new(); for font_path in font_paths { diff --git a/crates/terminal2/src/mappings/colors.rs b/crates/terminal2/src/mappings/colors.rs index fc3557b4e80c3095c8cc63278d0a86e250230362..d3c8443cbf962c68dc3dd124aff2495d0a88ddc0 100644 --- a/crates/terminal2/src/mappings/colors.rs +++ b/crates/terminal2/src/mappings/colors.rs @@ -1,6 +1,6 @@ // todo!() use alacritty_terminal::term::color::Rgb as AlacRgb; -// use gpui2::color::Color; +// use gpui::color::Color; // use theme2::TerminalStyle; ///Converts a 2, 8, or 24 bit color ANSI color to the GPUI equivalent diff --git a/crates/ui2/Cargo.toml b/crates/ui2/Cargo.toml index f11fd652b61d4b5be02ef0f06eb0095a3c3fda44..754bca371f41e741356f1ad9df670de2154e9978 100644 --- a/crates/ui2/Cargo.toml +++ b/crates/ui2/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] anyhow.workspace = true chrono = "0.4" -gpui2 = { path = "../gpui2" } +gpui = { package = "gpui2", path = "../gpui2" } itertools = { version = "0.11.0", optional = true } serde.workspace = true settings2 = { path = "../settings2" } diff --git a/crates/ui2/docs/hello-world.md b/crates/ui2/docs/hello-world.md index c6ded9ce34144495e911736669b2e07d56acc346..e8ed3bb9445464e310e22dbc40d9773bf419d2b3 100644 --- a/crates/ui2/docs/hello-world.md +++ b/crates/ui2/docs/hello-world.md @@ -40,12 +40,12 @@ impl TodoList { All of this is relatively straightforward. -We use [gpui2::SharedString] in components instead of [std::string::String]. This allows us to [TODO: someone who actually knows please explain why we use SharedString]. +We use [gpui::SharedString] in components instead of [std::string::String]. This allows us to [TODO: someone who actually knows please explain why we use SharedString]. When we want to pass an action we pass a `ClickHandler`. Whenever we want to add an action, the struct it belongs to needs to be generic over the view type `V`. ~~~rust -use gpui2::hsla +use gpui::hsla impl TodoList { // ... @@ -74,7 +74,7 @@ As you start using the Tailwind-style conventions you will be surprised how quic **Why `50.0/360.0` in `hsla()`?** -gpui [gpui2::Hsla] use `0.0-1.0` for all it's values, but it is common for tools to use `0-360` for hue. +gpui [gpui::Hsla] use `0.0-1.0` for all it's values, but it is common for tools to use `0-360` for hue. This may change in the future, but this is a little trick that let's you use familiar looking values. @@ -98,7 +98,7 @@ impl TodoList { Now we have access to the complete set of colors defined in the theme. ~~~rust -use gpui2::hsla +use gpui::hsla impl TodoList { // ... @@ -113,7 +113,7 @@ impl TodoList { Let's finish up some basic styles for the container then move on to adding the other elements. ~~~rust -use gpui2::hsla +use gpui::hsla impl TodoList { // ... diff --git a/crates/ui2/src/components/avatar.rs b/crates/ui2/src/components/avatar.rs index ff574a2042d2805a08a64867916b1cdea9802271..9c993dfc062c2df288c5345c8bcc4019cd11d6a4 100644 --- a/crates/ui2/src/components/avatar.rs +++ b/crates/ui2/src/components/avatar.rs @@ -1,4 +1,4 @@ -use gpui2::img; +use gpui::img; use crate::prelude::*; @@ -33,7 +33,7 @@ impl Avatar { img.uri(self.src.clone()) .size_4() // todo!(Pull the avatar fallback background from the theme.) - .bg(gpui2::red()) + .bg(gpui::red()) } } @@ -44,7 +44,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct AvatarStory; diff --git a/crates/ui2/src/components/button.rs b/crates/ui2/src/components/button.rs index 178813dd5fc424715af72ebbf35c9fb535af21ed..437daaa982b21d4e938c3ca823fe2a40432427b3 100644 --- a/crates/ui2/src/components/button.rs +++ b/crates/ui2/src/components/button.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use gpui2::{div, rems, DefiniteLength, Hsla, MouseButton, WindowContext}; +use gpui::{div, rems, DefiniteLength, Hsla, MouseButton, WindowContext}; use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor, LineHeightStyle}; use crate::{prelude::*, IconButton}; @@ -234,7 +234,7 @@ pub use stories::*; mod stories { use super::*; use crate::{h_stack, v_stack, LabelColor, Story}; - use gpui2::{rems, Div, Render}; + use gpui::{rems, Div, Render}; use strum::IntoEnumIterator; pub struct ButtonStory; diff --git a/crates/ui2/src/components/checkbox.rs b/crates/ui2/src/components/checkbox.rs index 9632a6681066f06e35bebfb834dd78ab9b983929..9f7c10a10433eef59249e3ab0df408b94a8a2aff 100644 --- a/crates/ui2/src/components/checkbox.rs +++ b/crates/ui2/src/components/checkbox.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use gpui2::{ +use gpui::{ div, Component, ElementId, ParentElement, StatefulInteractive, StatelessInteractive, Styled, ViewContext, }; @@ -175,7 +175,7 @@ pub use stories::*; mod stories { use super::*; use crate::{h_stack, Story}; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct CheckboxStory; diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 87be445c1990c486345d96263976080b1d96b157..117be127798bd56f9d0c3963f8119832aa170550 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -65,7 +65,7 @@ pub use stories::*; mod stories { use super::*; use crate::story::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct ContextMenuStory; diff --git a/crates/ui2/src/components/details.rs b/crates/ui2/src/components/details.rs index 1d22c817740804b7dd2e2a6121d130e28b336dbe..c7f6cc1839df780cef995a1e98b9b3f68aa3ca57 100644 --- a/crates/ui2/src/components/details.rs +++ b/crates/ui2/src/components/details.rs @@ -47,7 +47,7 @@ pub use stories::*; mod stories { use super::*; use crate::{Button, Story}; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct DetailsStory; diff --git a/crates/ui2/src/components/facepile.rs b/crates/ui2/src/components/facepile.rs index 21dd848a281a2ed655c473c53f980958e778de75..efac4925f80a579bfc9deeca273fbf64aad10c5f 100644 --- a/crates/ui2/src/components/facepile.rs +++ b/crates/ui2/src/components/facepile.rs @@ -33,7 +33,7 @@ pub use stories::*; mod stories { use super::*; use crate::{static_players, Story}; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct FacepileStory; diff --git a/crates/ui2/src/components/icon.rs b/crates/ui2/src/components/icon.rs index fa1e1c63151a2ad4a80a4e68382f2137a28d9be1..907f3f91871b5c614944e821244d10228d2853bb 100644 --- a/crates/ui2/src/components/icon.rs +++ b/crates/ui2/src/components/icon.rs @@ -1,4 +1,4 @@ -use gpui2::{rems, svg, Hsla}; +use gpui::{rems, svg, Hsla}; use strum::EnumIter; use crate::prelude::*; @@ -204,7 +204,7 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::{Div, Render}; + use gpui::{Div, Render}; use strum::IntoEnumIterator; use crate::Story; diff --git a/crates/ui2/src/components/icon_button.rs b/crates/ui2/src/components/icon_button.rs index 8fe1a1fa9bc37d08002ed07e07bb167e05a2bd2e..cb4fb4d7f00463b6a8b4dd0d661fb77d82c62419 100644 --- a/crates/ui2/src/components/icon_button.rs +++ b/crates/ui2/src/components/icon_button.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use gpui2::{rems, MouseButton}; +use gpui::{rems, MouseButton}; use crate::{h_stack, prelude::*}; use crate::{ClickHandler, Icon, IconColor, IconElement}; diff --git a/crates/ui2/src/components/indicator.rs b/crates/ui2/src/components/indicator.rs index 94398ab7f6016640d55e20a69d8e6939ca75c51a..83030ebbee066b213ab9594106b7c6610e7f64e3 100644 --- a/crates/ui2/src/components/indicator.rs +++ b/crates/ui2/src/components/indicator.rs @@ -1,4 +1,4 @@ -use gpui2::px; +use gpui::px; use crate::prelude::*; diff --git a/crates/ui2/src/components/input.rs b/crates/ui2/src/components/input.rs index f288f3ca563d861bfb9b17e38d9ea7b9a2bea40a..e9f520346c5bb2d036d3f754f13c9452406266c5 100644 --- a/crates/ui2/src/components/input.rs +++ b/crates/ui2/src/components/input.rs @@ -111,7 +111,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct InputStory; diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index 8b8fba8c08d2da0ab097a82adc0a852925f1c30f..22bbc747a2e5d503d46aff06b9ba1d03d8de5e0b 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -158,7 +158,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; use itertools::Itertools; pub struct KeybindingStory; diff --git a/crates/ui2/src/components/label.rs b/crates/ui2/src/components/label.rs index d1d4d6630c49437979421de52b370a67be5d78ac..dd078d2331305dcfd87a66a52c290b0bfe8cb1fa 100644 --- a/crates/ui2/src/components/label.rs +++ b/crates/ui2/src/components/label.rs @@ -1,4 +1,4 @@ -use gpui2::{relative, rems, Hsla, WindowContext}; +use gpui::{relative, rems, Hsla, WindowContext}; use smallvec::SmallVec; use crate::prelude::*; @@ -194,7 +194,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct LabelStory; diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index b30beacd9837af2bf6fa83e5810425cde600c010..c11860e9a5a653025f0f2fbae7c5733dd6f21537 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -1,4 +1,4 @@ -use gpui2::div; +use gpui::div; use crate::settings::user_settings; use crate::{ diff --git a/crates/ui2/src/components/modal.rs b/crates/ui2/src/components/modal.rs index 26986474e09dc012b039d36325347a33c7924f4e..75528b5c3460defeb139f7a16d8d311d87a5093b 100644 --- a/crates/ui2/src/components/modal.rs +++ b/crates/ui2/src/components/modal.rs @@ -1,4 +1,4 @@ -use gpui2::AnyElement; +use gpui::AnyElement; use smallvec::SmallVec; use crate::{h_stack, prelude::*, v_stack, Button, Icon, IconButton, Label}; diff --git a/crates/ui2/src/components/notification_toast.rs b/crates/ui2/src/components/notification_toast.rs index e8739b925c7e03c2a4fb2eb77cf005ea72ec665e..aeb2aa6ed901f8f867109f6687e100d0dc061ccb 100644 --- a/crates/ui2/src/components/notification_toast.rs +++ b/crates/ui2/src/components/notification_toast.rs @@ -1,4 +1,4 @@ -use gpui2::rems; +use gpui::rems; use crate::prelude::*; use crate::{h_stack, Icon}; diff --git a/crates/ui2/src/components/palette.rs b/crates/ui2/src/components/palette.rs index 269b39d86d5bc4fbbfa34fa20f9418a335b47641..7f736433fcd4d376534e265d3bf412aaa068888c 100644 --- a/crates/ui2/src/components/palette.rs +++ b/crates/ui2/src/components/palette.rs @@ -153,13 +153,13 @@ impl PaletteItem { } } -use gpui2::ElementId; +use gpui::ElementId; #[cfg(feature = "stories")] pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::{Div, Render}; + use gpui::{Div, Render}; use crate::{ModifierKeys, Story}; diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index ba88abb337259e2e56d1b9b5e1eabb169fc0827c..1762003a2c2f8b6a8569a5ffd99770d90aef130d 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -1,4 +1,4 @@ -use gpui2::{AbsoluteLength, AnyElement}; +use gpui::{AbsoluteLength, AnyElement}; use smallvec::SmallVec; use crate::prelude::*; @@ -126,7 +126,7 @@ pub use stories::*; mod stories { use super::*; use crate::{Label, Story}; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct PanelStory; diff --git a/crates/ui2/src/components/player.rs b/crates/ui2/src/components/player.rs index b6c80400cf373dd716cc9cb1686a7aee8af05cc0..dc034a5373e5347fa214a57f6e025326c89f62f8 100644 --- a/crates/ui2/src/components/player.rs +++ b/crates/ui2/src/components/player.rs @@ -1,4 +1,4 @@ -use gpui2::{Hsla, ViewContext}; +use gpui::{Hsla, ViewContext}; use crate::prelude::*; diff --git a/crates/ui2/src/components/slot.rs b/crates/ui2/src/components/slot.rs index f980e2fbda51a3b86ae5d677ac5838cb94ea09d2..a672694dc5781c6a474211d621a71ee640e7dcaa 100644 --- a/crates/ui2/src/components/slot.rs +++ b/crates/ui2/src/components/slot.rs @@ -1,4 +1,4 @@ -use gpui2::SharedString; +use gpui::SharedString; use crate::Icon; diff --git a/crates/ui2/src/components/stack.rs b/crates/ui2/src/components/stack.rs index 1b019ad4d949f838c1afc1b4c995edcc0a5a2f1a..d7bd0eb04f23b67b0797d86ba04fe3f4ee818b84 100644 --- a/crates/ui2/src/components/stack.rs +++ b/crates/ui2/src/components/stack.rs @@ -1,4 +1,4 @@ -use gpui2::{div, Div}; +use gpui::{div, Div}; use crate::prelude::*; diff --git a/crates/ui2/src/components/tab.rs b/crates/ui2/src/components/tab.rs index 47de0541f1d6287a0e800c298e45c76486c3ef57..416db2d17294d5c62e654f136b3f82c714f43b85 100644 --- a/crates/ui2/src/components/tab.rs +++ b/crates/ui2/src/components/tab.rs @@ -1,6 +1,6 @@ use crate::prelude::*; use crate::{Icon, IconColor, IconElement, Label, LabelColor}; -use gpui2::{red, Div, ElementId, Render, View, VisualContext}; +use gpui::{red, Div, ElementId, Render, View, VisualContext}; #[derive(Component, Clone)] pub struct Tab { diff --git a/crates/ui2/src/components/toast.rs b/crates/ui2/src/components/toast.rs index 4ab6625dbaed89311a78227610b27434f91f7925..4164be2c3e71fdf22b0b9a852588b796d0d1de21 100644 --- a/crates/ui2/src/components/toast.rs +++ b/crates/ui2/src/components/toast.rs @@ -1,4 +1,4 @@ -use gpui2::AnyElement; +use gpui::AnyElement; use smallvec::SmallVec; use crate::prelude::*; @@ -70,7 +70,7 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::{Div, Render}; + use gpui::{Div, Render}; use crate::{Label, Story}; diff --git a/crates/ui2/src/components/toggle.rs b/crates/ui2/src/components/toggle.rs index adde36758159cf6a1ea93ec2f152f0dfcf904f6b..368c95662fa51ed804c3d73f0d456d4f071a76d1 100644 --- a/crates/ui2/src/components/toggle.rs +++ b/crates/ui2/src/components/toggle.rs @@ -1,4 +1,4 @@ -use gpui2::{div, Component, ParentElement}; +use gpui::{div, Component, ParentElement}; use crate::{Icon, IconColor, IconElement, IconSize}; diff --git a/crates/ui2/src/components/tooltip.rs b/crates/ui2/src/components/tooltip.rs index c05214eea4e8d977ab85d875b341e1165a785b3a..84630920128a3a107a31e5a7fecb8dca2b139037 100644 --- a/crates/ui2/src/components/tooltip.rs +++ b/crates/ui2/src/components/tooltip.rs @@ -1,4 +1,4 @@ -use gpui2::{div, px, Div, ParentElement, Render, SharedString, Styled, ViewContext}; +use gpui::{div, px, Div, ParentElement, Render, SharedString, Styled, ViewContext}; use theme2::ActiveTheme; #[derive(Clone, Debug)] diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index 134b293d3daa0a5b14f5d3916e0ae44f77f291a3..c942f0aa3b883141a6178533c83e45c2a3a9f48c 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -1,4 +1,4 @@ -pub use gpui2::{ +pub use gpui::{ div, Component, Element, ElementId, ParentElement, SharedString, StatefulInteractive, StatelessInteractive, Styled, ViewContext, WindowContext, }; @@ -7,7 +7,7 @@ pub use crate::elevation::*; pub use crate::ButtonVariant; pub use theme2::ActiveTheme; -use gpui2::Hsla; +use gpui::Hsla; use strum::EnumIter; #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)] diff --git a/crates/ui2/src/settings.rs b/crates/ui2/src/settings.rs index 6a9426f623ef167d8ec3a24054d2586f1536b7f1..c3ac78316e9e6138195225c92cdad96542e808cd 100644 --- a/crates/ui2/src/settings.rs +++ b/crates/ui2/src/settings.rs @@ -1,6 +1,6 @@ use std::ops::Deref; -use gpui2::{rems, AbsoluteLength, AppContext, WindowContext}; +use gpui::{rems, AbsoluteLength, AppContext, WindowContext}; use crate::prelude::*; diff --git a/crates/ui2/src/static_data.rs b/crates/ui2/src/static_data.rs index 5342e1fb165606a8316fbb542aad2b78104ec4ea..ffdd3fee9849147719f89dcf08c23bff17dee4d9 100644 --- a/crates/ui2/src/static_data.rs +++ b/crates/ui2/src/static_data.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use std::sync::Arc; use chrono::DateTime; -use gpui2::{AppContext, ViewContext}; +use gpui::{AppContext, ViewContext}; use rand::Rng; use theme2::ActiveTheme; diff --git a/crates/ui2/src/story.rs b/crates/ui2/src/story.rs index dea4e342b4eda0520251c3685e8dbd50be2aedb2..94e38267f4c5b160365317c4e597a76748c05d6f 100644 --- a/crates/ui2/src/story.rs +++ b/crates/ui2/src/story.rs @@ -1,4 +1,4 @@ -use gpui2::Div; +use gpui::Div; use crate::prelude::*; diff --git a/crates/ui2/src/to_extract/assistant_panel.rs b/crates/ui2/src/to_extract/assistant_panel.rs index 51c123ad9ea7db7947673e3905313fdfa28bfcfc..8a35757f5c484315daebea12c0af7186c418f96e 100644 --- a/crates/ui2/src/to_extract/assistant_panel.rs +++ b/crates/ui2/src/to_extract/assistant_panel.rs @@ -1,6 +1,6 @@ use crate::prelude::*; use crate::{Icon, IconButton, Label, Panel, PanelSide}; -use gpui2::{rems, AbsoluteLength}; +use gpui::{rems, AbsoluteLength}; #[derive(Component)] pub struct AssistantPanel { @@ -77,7 +77,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct AssistantPanelStory; impl Render for AssistantPanelStory { diff --git a/crates/ui2/src/to_extract/breadcrumb.rs b/crates/ui2/src/to_extract/breadcrumb.rs index 163dfabfb0b5ed73e72df5346f998c1e1cf7b651..cd7df87646a026f352d580ef47e1c1ef90fdb441 100644 --- a/crates/ui2/src/to_extract/breadcrumb.rs +++ b/crates/ui2/src/to_extract/breadcrumb.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use crate::prelude::*; use crate::{h_stack, HighlightedText}; -use gpui2::Div; +use gpui::Div; #[derive(Clone)] pub struct Symbol(pub Vec); @@ -73,7 +73,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::Render; + use gpui::Render; use std::str::FromStr; pub struct BreadcrumbStory; diff --git a/crates/ui2/src/to_extract/buffer.rs b/crates/ui2/src/to_extract/buffer.rs index e12beff2fce5e8c8d081c44e832c3a19465e7b3f..8ab435e9947bb4746613a4f1fd1ba2f5576a2a9f 100644 --- a/crates/ui2/src/to_extract/buffer.rs +++ b/crates/ui2/src/to_extract/buffer.rs @@ -1,4 +1,4 @@ -use gpui2::{Hsla, WindowContext}; +use gpui::{Hsla, WindowContext}; use crate::prelude::*; use crate::{h_stack, v_stack, Icon, IconElement}; @@ -235,7 +235,7 @@ mod stories { empty_buffer_example, hello_world_rust_buffer_example, hello_world_rust_buffer_with_status_example, Story, }; - use gpui2::{rems, Div, Render}; + use gpui::{rems, Div, Render}; pub struct BufferStory; diff --git a/crates/ui2/src/to_extract/buffer_search.rs b/crates/ui2/src/to_extract/buffer_search.rs index 02f689ca3e009bca7dbedc6fc015b185321e8f90..9993cd361294067112c6b629ef9f5e2698e4e3cb 100644 --- a/crates/ui2/src/to_extract/buffer_search.rs +++ b/crates/ui2/src/to_extract/buffer_search.rs @@ -1,4 +1,4 @@ -use gpui2::{Div, Render, View, VisualContext}; +use gpui::{Div, Render, View, VisualContext}; use crate::prelude::*; use crate::{h_stack, Icon, IconButton, IconColor, Input}; diff --git a/crates/ui2/src/to_extract/chat_panel.rs b/crates/ui2/src/to_extract/chat_panel.rs index f4f1ddf4337c30f5fcfc5f19d1731c846ab3a5f8..538b5dfceba5bb753feb0504b1eb880140aef291 100644 --- a/crates/ui2/src/to_extract/chat_panel.rs +++ b/crates/ui2/src/to_extract/chat_panel.rs @@ -108,7 +108,7 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { use chrono::DateTime; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; use crate::{Panel, Story}; diff --git a/crates/ui2/src/to_extract/collab_panel.rs b/crates/ui2/src/to_extract/collab_panel.rs index 9d9dc861e2a1c2ce073040334e6ccaaf5ab2562e..7b785ae9e1dbbda8c5392baa1473a7a31d6ce1eb 100644 --- a/crates/ui2/src/to_extract/collab_panel.rs +++ b/crates/ui2/src/to_extract/collab_panel.rs @@ -92,7 +92,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct CollabPanelStory; diff --git a/crates/ui2/src/to_extract/command_palette.rs b/crates/ui2/src/to_extract/command_palette.rs index 63db4359e7e84c6608f737bc1e3762f2d4b53eec..8a9461c796d053e45fb768f3db4c14f1364f0d27 100644 --- a/crates/ui2/src/to_extract/command_palette.rs +++ b/crates/ui2/src/to_extract/command_palette.rs @@ -27,7 +27,7 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::{Div, Render}; + use gpui::{Div, Render}; use crate::Story; diff --git a/crates/ui2/src/to_extract/copilot.rs b/crates/ui2/src/to_extract/copilot.rs index 51523d48f07bf9f7c4eed4d5edf07f0b7ff7fb3b..8750ab3c51a28cd1f91f67f09c4cd7d419a7b98b 100644 --- a/crates/ui2/src/to_extract/copilot.rs +++ b/crates/ui2/src/to_extract/copilot.rs @@ -25,7 +25,7 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::{Div, Render}; + use gpui::{Div, Render}; use crate::Story; diff --git a/crates/ui2/src/to_extract/editor_pane.rs b/crates/ui2/src/to_extract/editor_pane.rs index 8e54d2c2e888f5b75599d85f779d9ebae3c96ad7..fd21e81242c34237f9d16fb63f66312ebc678fbf 100644 --- a/crates/ui2/src/to_extract/editor_pane.rs +++ b/crates/ui2/src/to_extract/editor_pane.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use gpui2::{Div, Render, View, VisualContext}; +use gpui::{Div, Render, View, VisualContext}; use crate::prelude::*; use crate::{ diff --git a/crates/ui2/src/to_extract/language_selector.rs b/crates/ui2/src/to_extract/language_selector.rs index fa7f5b2bd7b9cae4135f321e34ad559834f8d539..694ca78e9c92353a7097f33d7ec133278b063bb0 100644 --- a/crates/ui2/src/to_extract/language_selector.rs +++ b/crates/ui2/src/to_extract/language_selector.rs @@ -40,7 +40,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct LanguageSelectorStory; diff --git a/crates/ui2/src/to_extract/multi_buffer.rs b/crates/ui2/src/to_extract/multi_buffer.rs index 1334703015b1373255ba5113bcce143ee790413b..78a22d51d078bc6293e849f8898b53ee2c363109 100644 --- a/crates/ui2/src/to_extract/multi_buffer.rs +++ b/crates/ui2/src/to_extract/multi_buffer.rs @@ -40,7 +40,7 @@ pub use stories::*; mod stories { use super::*; use crate::{hello_world_rust_buffer_example, Story}; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct MultiBufferStory; diff --git a/crates/ui2/src/to_extract/notifications_panel.rs b/crates/ui2/src/to_extract/notifications_panel.rs index 84794b71b21993cf1c41e9e15d8d388c39d5a140..b2cc4a7846c00acf32b4afb1d65d196f8caeda8a 100644 --- a/crates/ui2/src/to_extract/notifications_panel.rs +++ b/crates/ui2/src/to_extract/notifications_panel.rs @@ -345,7 +345,7 @@ impl Notification { } use chrono::NaiveDateTime; -use gpui2::{px, Styled}; +use gpui::{px, Styled}; #[cfg(feature = "stories")] pub use stories::*; @@ -353,7 +353,7 @@ pub use stories::*; mod stories { use super::*; use crate::{Panel, Story}; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct NotificationsPanelStory; diff --git a/crates/ui2/src/to_extract/panes.rs b/crates/ui2/src/to_extract/panes.rs index a1e040b0cad9a5365548feb150f1084f4fa3404e..b57b77d5eeb8ec71dc4ab075d63269fcac158cbe 100644 --- a/crates/ui2/src/to_extract/panes.rs +++ b/crates/ui2/src/to_extract/panes.rs @@ -1,4 +1,4 @@ -use gpui2::{hsla, red, AnyElement, ElementId, ExternalPaths, Hsla, Length, Size, View}; +use gpui::{hsla, red, AnyElement, ElementId, ExternalPaths, Hsla, Length, Size, View}; use smallvec::SmallVec; use crate::prelude::*; diff --git a/crates/ui2/src/to_extract/project_panel.rs b/crates/ui2/src/to_extract/project_panel.rs index a34a30bcbcf0ae71a19caff2884039933d1bcce4..d4f5c724265f549eaed54040364abf655c6a5bfd 100644 --- a/crates/ui2/src/to_extract/project_panel.rs +++ b/crates/ui2/src/to_extract/project_panel.rs @@ -46,7 +46,7 @@ impl ProjectPanel { } } -use gpui2::ElementId; +use gpui::ElementId; #[cfg(feature = "stories")] pub use stories::*; @@ -54,7 +54,7 @@ pub use stories::*; mod stories { use super::*; use crate::{Panel, Story}; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct ProjectPanelStory; diff --git a/crates/ui2/src/to_extract/recent_projects.rs b/crates/ui2/src/to_extract/recent_projects.rs index d5a9dd1b228122db6475d434b897e48392d0d38a..3d4f551490a47ef5eab616ebf1e2b1f6f0a0a726 100644 --- a/crates/ui2/src/to_extract/recent_projects.rs +++ b/crates/ui2/src/to_extract/recent_projects.rs @@ -36,7 +36,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct RecentProjectsStory; diff --git a/crates/ui2/src/to_extract/tab_bar.rs b/crates/ui2/src/to_extract/tab_bar.rs index a1280441832f1a6a8caee0c1a63ec989d021ad37..aff095c639ea48c560b35e738e18f60ea38e8264 100644 --- a/crates/ui2/src/to_extract/tab_bar.rs +++ b/crates/ui2/src/to_extract/tab_bar.rs @@ -92,7 +92,7 @@ impl TabBar { } } -use gpui2::ElementId; +use gpui::ElementId; #[cfg(feature = "stories")] pub use stories::*; @@ -100,7 +100,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct TabBarStory; diff --git a/crates/ui2/src/to_extract/terminal.rs b/crates/ui2/src/to_extract/terminal.rs index b912a5960768e3b17a11988560a0201ac6ee2902..6c36f35152d8082a3da7fda855a5fc58084b3ae2 100644 --- a/crates/ui2/src/to_extract/terminal.rs +++ b/crates/ui2/src/to_extract/terminal.rs @@ -1,4 +1,4 @@ -use gpui2::{relative, rems, Size}; +use gpui::{relative, rems, Size}; use crate::prelude::*; use crate::{Icon, IconButton, Pane, Tab}; @@ -83,7 +83,7 @@ pub use stories::*; mod stories { use super::*; use crate::Story; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; pub struct TerminalStory; impl Render for TerminalStory { diff --git a/crates/ui2/src/to_extract/theme_selector.rs b/crates/ui2/src/to_extract/theme_selector.rs index 5c67f1cd3ef987c5181734fedfdf061cf50465fe..7f911b50bfa8d9b6273126053a7e791e41754989 100644 --- a/crates/ui2/src/to_extract/theme_selector.rs +++ b/crates/ui2/src/to_extract/theme_selector.rs @@ -39,7 +39,7 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::{Div, Render}; + use gpui::{Div, Render}; use crate::Story; diff --git a/crates/ui2/src/to_extract/title_bar.rs b/crates/ui2/src/to_extract/title_bar.rs index 2fa201440a9ca0301cb6b7c04ca9246597f9c409..87d7dd4146d051aa5c8e4b8ae6697f487bfb34fa 100644 --- a/crates/ui2/src/to_extract/title_bar.rs +++ b/crates/ui2/src/to_extract/title_bar.rs @@ -1,7 +1,7 @@ use std::sync::atomic::AtomicBool; use std::sync::Arc; -use gpui2::{Div, Render, View, VisualContext}; +use gpui::{Div, Render, View, VisualContext}; use crate::prelude::*; use crate::settings::user_settings; diff --git a/crates/ui2/src/to_extract/toolbar.rs b/crates/ui2/src/to_extract/toolbar.rs index 0e3e7c259ff971622feb5b89fbeddc3bf5023a2f..81918f34a790b1ec91aa4ac33cad210972b191cf 100644 --- a/crates/ui2/src/to_extract/toolbar.rs +++ b/crates/ui2/src/to_extract/toolbar.rs @@ -1,4 +1,4 @@ -use gpui2::AnyElement; +use gpui::AnyElement; use smallvec::SmallVec; use crate::prelude::*; @@ -73,7 +73,7 @@ mod stories { use std::path::PathBuf; use std::str::FromStr; - use gpui2::{Div, Render}; + use gpui::{Div, Render}; use crate::{Breadcrumb, HighlightedText, Icon, IconButton, Story, Symbol}; diff --git a/crates/ui2/src/to_extract/traffic_lights.rs b/crates/ui2/src/to_extract/traffic_lights.rs index 677fae886c838c03cc42ed300ce9df4f79d1d883..245ff377f2146579f5532123a456f2f1ae498cfc 100644 --- a/crates/ui2/src/to_extract/traffic_lights.rs +++ b/crates/ui2/src/to_extract/traffic_lights.rs @@ -77,7 +77,7 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::{Div, Render}; + use gpui::{Div, Render}; use crate::Story; diff --git a/crates/ui2/src/to_extract/workspace.rs b/crates/ui2/src/to_extract/workspace.rs index 77b9bc45393db4d905be3c3c08c8c2b18150f4e8..d6de8a828807606a6d55086af724983ca1a93df0 100644 --- a/crates/ui2/src/to_extract/workspace.rs +++ b/crates/ui2/src/to_extract/workspace.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use chrono::DateTime; -use gpui2::{px, relative, Div, Render, Size, View, VisualContext}; +use gpui::{px, relative, Div, Render, Size, View, VisualContext}; use settings2::Settings; use theme2::ThemeSettings; @@ -373,7 +373,7 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { use super::*; - use gpui2::VisualContext; + use gpui::VisualContext; pub struct WorkspaceStory { workspace: View, diff --git a/crates/zed2/src/languages/language_plugin.rs b/crates/zed2/src/languages/language_plugin.rs index a160cca228faa2d91285ec5ed1e8b499833cffd6..968cc819fde558f939de6c7f655023e0b431bd37 100644 --- a/crates/zed2/src/languages/language_plugin.rs +++ b/crates/zed2/src/languages/language_plugin.rs @@ -2,7 +2,7 @@ use anyhow::{anyhow, Result}; use async_trait::async_trait; use collections::HashMap; use futures::lock::Mutex; -use gpui2::executor::Background; +use gpui::executor::Background; use language2::{LanguageServerName, LspAdapter, LspAdapterDelegate}; use lsp2::LanguageServerBinary; use plugin_runtime::{Plugin, PluginBinary, PluginBuilder, WasiFn}; diff --git a/test.rs b/test.rs index 6553e633c8e82597b9ca32b34d68a2f475d586ce..4a7b9faa8ff9b56cc0779b79f5152b3b1694c2c7 100644 --- a/test.rs +++ b/test.rs @@ -410,7 +410,7 @@ mod components { themes::rose_pine, }; use gpui::{platform::MouseButton, ViewContext}; - use gpui2_macros::Element; + use gpui_macros::Element; use std::{marker::PhantomData, rc::Rc}; struct ButtonHandlers { click: Option)>>, @@ -535,7 +535,7 @@ mod element { platform::{MouseButton, MouseButtonEvent}, EngineLayout, EventContext, RenderContext, ViewContext, }; - use gpui2_macros::tailwind_lengths; + use gpui_macros::tailwind_lengths; use std::{ any::{Any, TypeId}, cell::Cell, @@ -4572,7 +4572,7 @@ mod frame { }; use anyhow::{anyhow, Result}; use gpui::LayoutNodeId; - use gpui2_macros::IntoElement; + use gpui_macros::IntoElement; #[element_crate = "crate"] pub struct Frame { style: OptionalStyle,