diff --git a/crates/command_palette2/src/command_palette.rs b/crates/command_palette2/src/command_palette.rs index 07b819d3a1..a393c519be 100644 --- a/crates/command_palette2/src/command_palette.rs +++ b/crates/command_palette2/src/command_palette.rs @@ -1,17 +1,17 @@ use collections::{CommandPaletteFilter, HashMap}; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ - actions, div, prelude::*, Action, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, - FocusableView, Keystroke, ParentElement, Render, Styled, View, ViewContext, VisualContext, - WeakView, + actions, div, prelude::*, Action, AnyElement, AppContext, DismissEvent, Div, EventEmitter, + FocusHandle, FocusableView, Keystroke, ParentElement, Render, Styled, View, ViewContext, + VisualContext, WeakView, }; -use picker::{Picker, PickerDelegate}; +use picker::{simple_picker_match, Picker, PickerDelegate}; use std::{ cmp::{self, Reverse}, sync::Arc, }; -use theme::ActiveTheme; -use ui::{h_stack, v_stack, HighlightedLabel, KeyBinding, StyledExt}; + +use ui::{h_stack, v_stack, HighlightedLabel, KeyBinding}; use util::{ channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL}, ResultExt, @@ -141,8 +141,6 @@ impl CommandPaletteDelegate { } impl PickerDelegate for CommandPaletteDelegate { - type ListItem = Div; - fn placeholder_text(&self) -> Arc { "Execute a command...".into() } @@ -294,32 +292,24 @@ impl PickerDelegate for CommandPaletteDelegate { ix: usize, selected: bool, cx: &mut ViewContext>, - ) -> Self::ListItem { - let colors = cx.theme().colors(); + ) -> AnyElement { let Some(r#match) = self.matches.get(ix) else { - return div(); + return div().into_any(); }; let Some(command) = self.commands.get(r#match.candidate_id) else { - return div(); + return div().into_any(); }; - div() - .px_1() - .text_color(colors.text) - .text_ui() - .bg(colors.ghost_element_background) - .rounded_md() - .when(selected, |this| this.bg(colors.ghost_element_selected)) - .hover(|this| this.bg(colors.ghost_element_hover)) - .child( - h_stack() - .justify_between() - .child(HighlightedLabel::new( - command.name.clone(), - r#match.positions.clone(), - )) - .children(KeyBinding::for_action(&*command.action, cx)), - ) + simple_picker_match(selected, cx, |cx| { + h_stack() + .justify_between() + .child(HighlightedLabel::new( + command.name.clone(), + r#match.positions.clone(), + )) + .children(KeyBinding::for_action(&*command.action, cx)) + .into_any() + }) } } diff --git a/crates/file_finder2/src/file_finder.rs b/crates/file_finder2/src/file_finder.rs index ea578fbb0e..c93d29ffec 100644 --- a/crates/file_finder2/src/file_finder.rs +++ b/crates/file_finder2/src/file_finder.rs @@ -2,9 +2,9 @@ use collections::HashMap; use editor::{scroll::autoscroll::Autoscroll, Bias, Editor}; use fuzzy::{CharBag, PathMatch, PathMatchCandidate}; use gpui::{ - actions, div, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView, - InteractiveElement, IntoElement, Model, ParentElement, Render, Styled, Task, View, ViewContext, - VisualContext, WeakView, + actions, div, AnyElement, AppContext, DismissEvent, Div, Element, EventEmitter, FocusHandle, + FocusableView, InteractiveElement, IntoElement, Model, ParentElement, Render, Styled, Task, + View, ViewContext, VisualContext, WeakView, }; use picker::{Picker, PickerDelegate}; use project::{PathMatchCandidateSet, Project, ProjectPath, WorktreeId}; @@ -530,8 +530,6 @@ impl FileFinderDelegate { } impl PickerDelegate for FileFinderDelegate { - type ListItem = Div; - fn placeholder_text(&self) -> Arc { "Search project files...".into() } @@ -711,7 +709,7 @@ impl PickerDelegate for FileFinderDelegate { ix: usize, selected: bool, cx: &mut ViewContext>, - ) -> Self::ListItem { + ) -> AnyElement { let path_match = self .matches .get(ix) @@ -735,6 +733,7 @@ impl PickerDelegate for FileFinderDelegate { .child(HighlightedLabel::new(file_name, file_name_positions)) .child(HighlightedLabel::new(full_path, full_path_positions)), ) + .into_any() } } diff --git a/crates/picker2/src/picker2.rs b/crates/picker2/src/picker2.rs index dc6b77c7c7..76d902da45 100644 --- a/crates/picker2/src/picker2.rs +++ b/crates/picker2/src/picker2.rs @@ -1,7 +1,8 @@ use editor::Editor; use gpui::{ - div, prelude::*, uniform_list, AppContext, Div, FocusHandle, FocusableView, MouseButton, - MouseDownEvent, Render, Task, UniformListScrollHandle, View, ViewContext, WindowContext, + div, prelude::*, uniform_list, AnyElement, AppContext, Div, FocusHandle, FocusableView, + MouseButton, MouseDownEvent, Render, Task, UniformListScrollHandle, View, ViewContext, + WindowContext, }; use std::{cmp, sync::Arc}; use ui::{prelude::*, v_stack, Color, Divider, Label}; @@ -15,8 +16,6 @@ pub struct Picker { } pub trait PickerDelegate: Sized + 'static { - type ListItem: IntoElement; - fn match_count(&self) -> usize; fn selected_index(&self) -> usize; fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext>); @@ -32,7 +31,7 @@ pub trait PickerDelegate: Sized + 'static { ix: usize, selected: bool, cx: &mut ViewContext>, - ) -> Self::ListItem; + ) -> AnyElement; } impl FocusableView for Picker { @@ -257,3 +256,22 @@ impl Render for Picker { }) } } + +pub fn simple_picker_match( + selected: bool, + cx: &mut WindowContext, + children: impl FnOnce(&mut WindowContext) -> AnyElement, +) -> AnyElement { + let colors = cx.theme().colors(); + + div() + .px_1() + .text_color(colors.text) + .text_ui() + .bg(colors.ghost_element_background) + .rounded_md() + .when(selected, |this| this.bg(colors.ghost_element_selected)) + .hover(|this| this.bg(colors.ghost_element_hover)) + .child((children)(cx)) + .into_any() +} diff --git a/crates/storybook2/src/stories/picker.rs b/crates/storybook2/src/stories/picker.rs index ae6a26161b..13822c8545 100644 --- a/crates/storybook2/src/stories/picker.rs +++ b/crates/storybook2/src/stories/picker.rs @@ -1,6 +1,7 @@ use fuzzy::StringMatchCandidate; use gpui::{ - div, prelude::*, Div, KeyBinding, Render, SharedString, Styled, Task, View, WindowContext, + div, prelude::*, AnyElement, Div, KeyBinding, Render, SharedString, Styled, Task, View, + WindowContext, }; use picker::{Picker, PickerDelegate}; use std::sync::Arc; @@ -36,8 +37,6 @@ impl Delegate { } impl PickerDelegate for Delegate { - type ListItem = Div; - fn match_count(&self) -> usize { self.candidates.len() } @@ -51,10 +50,10 @@ impl PickerDelegate for Delegate { ix: usize, selected: bool, cx: &mut gpui::ViewContext>, - ) -> Self::ListItem { + ) -> AnyElement { let colors = cx.theme().colors(); let Some(candidate_ix) = self.matches.get(ix) else { - return div(); + return div().into_any(); }; // TASK: Make StringMatchCandidate::string a SharedString let candidate = SharedString::from(self.candidates[*candidate_ix].string.clone()); @@ -70,6 +69,7 @@ impl PickerDelegate for Delegate { .text_color(colors.text_accent) }) .child(candidate) + .into_any() } fn selected_index(&self) -> usize { diff --git a/crates/theme_selector2/src/theme_selector.rs b/crates/theme_selector2/src/theme_selector.rs index 6e660caf51..1f3e6e92a1 100644 --- a/crates/theme_selector2/src/theme_selector.rs +++ b/crates/theme_selector2/src/theme_selector.rs @@ -2,39 +2,49 @@ use feature_flags::FeatureFlagAppExt; use fs::Fs; use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; use gpui::{ - actions, div, AppContext, Div, EventEmitter, FocusableView, Manager, Render, SharedString, - View, ViewContext, VisualContext, + actions, div, AnyElement, AppContext, DismissEvent, Element, EventEmitter, FocusableView, + InteractiveElement, IntoElement, ParentElement, Render, SharedString, Styled, View, + ViewContext, VisualContext, WeakView, }; use picker::{Picker, PickerDelegate}; use settings::{update_settings_file, SettingsStore}; use std::sync::Arc; use theme::{ActiveTheme, Theme, ThemeRegistry, ThemeSettings}; use util::ResultExt; -use workspace::{ui::HighlightedLabel, Workspace}; +use workspace::{ + ui::{HighlightedLabel, StyledExt}, + Workspace, +}; actions!(Toggle, Reload); pub fn init(cx: &mut AppContext) { cx.observe_new_views( - |workspace: &mut Workspace, cx: &mut ViewContext| { + |workspace: &mut Workspace, _cx: &mut ViewContext| { workspace.register_action(toggle); }, - ); + ) + .detach(); } pub fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext) { let fs = workspace.app_state().fs.clone(); workspace.toggle_modal(cx, |cx| { - ThemeSelector::new(ThemeSelectorDelegate::new(fs, cx), cx) + ThemeSelector::new( + ThemeSelectorDelegate::new(cx.view().downgrade(), fs, cx), + cx, + ) }); } #[cfg(debug_assertions)] pub fn reload(cx: &mut AppContext) { let current_theme_name = cx.theme().name.clone(); - let registry = cx.global::>(); - registry.clear(); - match registry.get(¤t_theme_name) { + let current_theme = cx.update_global(|registry: &mut ThemeRegistry, _cx| { + registry.clear(); + registry.get(¤t_theme_name) + }); + match current_theme { Ok(theme) => { ThemeSelectorDelegate::set_theme(theme, cx); log::info!("reloaded theme {}", current_theme_name); @@ -49,7 +59,7 @@ pub struct ThemeSelector { picker: View>, } -impl EventEmitter for ThemeSelector {} +impl EventEmitter for ThemeSelector {} impl FocusableView for ThemeSelector { fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { @@ -60,7 +70,7 @@ impl FocusableView for ThemeSelector { impl Render for ThemeSelector { type Element = View>; - fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + fn render(&mut self, _cx: &mut ViewContext) -> Self::Element { self.picker.clone() } } @@ -79,16 +89,22 @@ pub struct ThemeSelectorDelegate { original_theme: Arc, selection_completed: bool, selected_index: usize, + view: WeakView, } impl ThemeSelectorDelegate { - fn new(fs: Arc, cx: &mut ViewContext) -> Self { + fn new( + weak_view: WeakView, + fs: Arc, + cx: &mut ViewContext, + ) -> Self { let original_theme = cx.theme().clone(); let staff_mode = cx.is_staff(); let registry = cx.global::>(); - let mut theme_names = registry.list(staff_mode).collect::>(); - theme_names.sort_unstable_by(|a, b| a.is_light.cmp(&b.is_light).then(a.name.cmp(&b.name))); + let theme_names = registry.list(staff_mode).collect::>(); + //todo!(theme sorting) + // theme_names.sort_unstable_by(|a, b| a.is_light.cmp(&b.is_light).then(a.name.cmp(&b.name))); let matches = theme_names .iter() .map(|meta| StringMatch { @@ -105,12 +121,13 @@ impl ThemeSelectorDelegate { original_theme: original_theme.clone(), selected_index: 0, selection_completed: false, + view: weak_view, }; - this.select_if_matching(&original_theme.meta.name); + this.select_if_matching(&original_theme.name); this } - fn show_selected_theme(&mut self, cx: &mut ViewContext) { + fn show_selected_theme(&mut self, cx: &mut ViewContext>) { if let Some(mat) = self.matches.get(self.selected_index) { let registry = cx.global::>(); match registry.get(&mat.string) { @@ -133,18 +150,16 @@ impl ThemeSelectorDelegate { } fn set_theme(theme: Arc, cx: &mut AppContext) { - cx.update_global::(|store, cx| { + cx.update_global(|store: &mut SettingsStore, cx| { let mut theme_settings = store.get::(None).clone(); - theme_settings.theme = theme; + theme_settings.active_theme = theme; store.override_global(theme_settings); - cx.refresh_windows(); + cx.refresh(); }); } } impl PickerDelegate for ThemeSelectorDelegate { - type ListItem = Div; - fn placeholder_text(&self) -> Arc { "Select Theme...".into() } @@ -153,18 +168,22 @@ impl PickerDelegate for ThemeSelectorDelegate { self.matches.len() } - fn confirm(&mut self, _: bool, cx: &mut ViewContext) { + fn confirm(&mut self, _: bool, cx: &mut ViewContext>) { self.selection_completed = true; - let theme_name = cx.theme().meta.name.clone(); - update_settings_file::(self.fs.clone(), cx, |settings| { - settings.theme = Some(theme_name); + let theme_name = cx.theme().name.clone(); + update_settings_file::(self.fs.clone(), cx, move |settings| { + settings.theme = Some(theme_name.to_string()); }); - cx.emit(Manager::Dismiss); + self.view + .update(cx, |_, cx| { + cx.emit(DismissEvent::Dismiss); + }) + .ok(); } - fn dismissed(&mut self, cx: &mut ViewContext) { + fn dismissed(&mut self, cx: &mut ViewContext>) { if !self.selection_completed { Self::set_theme(self.original_theme.clone(), cx); self.selection_completed = true; @@ -175,7 +194,11 @@ impl PickerDelegate for ThemeSelectorDelegate { self.selected_index } - fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext) { + fn set_selected_index( + &mut self, + ix: usize, + cx: &mut ViewContext>, + ) { self.selected_index = ix; self.show_selected_theme(cx); } @@ -183,17 +206,17 @@ impl PickerDelegate for ThemeSelectorDelegate { fn update_matches( &mut self, query: String, - cx: &mut ViewContext, + cx: &mut ViewContext>, ) -> gpui::Task<()> { - let background = cx.background().clone(); + let background = cx.background_executor().clone(); let candidates = self .theme_names .iter() .enumerate() .map(|(id, meta)| StringMatchCandidate { id, - char_bag: meta.name.as_str().into(), - string: meta.name.clone(), + char_bag: meta.as_ref().into(), + string: meta.to_string(), }) .collect::>(); @@ -222,18 +245,23 @@ impl PickerDelegate for ThemeSelectorDelegate { }; this.update(&mut cx, |this, cx| { - let delegate = this.delegate_mut(); - delegate.matches = matches; - delegate.selected_index = delegate + this.delegate.matches = matches; + this.delegate.selected_index = this + .delegate .selected_index - .min(delegate.matches.len().saturating_sub(1)); - delegate.show_selected_theme(cx); + .min(this.delegate.matches.len().saturating_sub(1)); + this.delegate.show_selected_theme(cx); }) .log_err(); }) } - fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> Self::ListItem { + fn render_match( + &self, + ix: usize, + selected: bool, + cx: &mut ViewContext>, + ) -> AnyElement { let theme = cx.theme(); let colors = theme.colors(); @@ -250,5 +278,6 @@ impl PickerDelegate for ThemeSelectorDelegate { theme_match.string.clone(), theme_match.positions.clone(), )) + .into_any() } } diff --git a/crates/welcome2/src/base_keymap_picker.rs b/crates/welcome2/src/base_keymap_picker.rs index 021e3b86a0..b90478f960 100644 --- a/crates/welcome2/src/base_keymap_picker.rs +++ b/crates/welcome2/src/base_keymap_picker.rs @@ -1,22 +1,23 @@ use super::base_keymap_setting::BaseKeymap; use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; use gpui::{ - actions, - elements::{Element as _, Label}, - AppContext, Task, ViewContext, + actions, AppContext, DismissEvent, EventEmitter, FocusableView, IntoElement, Render, Task, + View, ViewContext, VisualContext, WeakView, }; -use picker::{Picker, PickerDelegate, PickerEvent}; +use picker::{simple_picker_match, Picker, PickerDelegate}; use project::Fs; -use settings::update_settings_file; +use settings::{update_settings_file, Settings}; use std::sync::Arc; use util::ResultExt; -use workspace::Workspace; +use workspace::{ui::HighlightedLabel, Workspace}; -actions!(welcome, [ToggleBaseKeymapSelector]); +actions!(ToggleBaseKeymapSelector); pub fn init(cx: &mut AppContext) { - cx.add_action(toggle); - BaseKeymapSelector::init(cx); + cx.observe_new_views(|workspace: &mut Workspace, _cx| { + workspace.register_action(toggle); + }) + .detach(); } pub fn toggle( @@ -24,28 +25,70 @@ pub fn toggle( _: &ToggleBaseKeymapSelector, cx: &mut ViewContext, ) { - workspace.toggle_modal(cx, |workspace, cx| { - let fs = workspace.app_state().fs.clone(); - cx.add_view(|cx| BaseKeymapSelector::new(BaseKeymapSelectorDelegate::new(fs, cx), cx)) + let fs = workspace.app_state().fs.clone(); + workspace.toggle_modal(cx, |cx| { + BaseKeymapSelector::new( + BaseKeymapSelectorDelegate::new(cx.view().downgrade(), fs, cx), + cx, + ) }); } -pub type BaseKeymapSelector = Picker; +pub struct BaseKeymapSelector { + focus_handle: gpui::FocusHandle, + picker: View>, +} + +impl FocusableView for BaseKeymapSelector { + fn focus_handle(&self, _cx: &AppContext) -> gpui::FocusHandle { + self.focus_handle.clone() + } +} + +impl EventEmitter for BaseKeymapSelector {} + +impl BaseKeymapSelector { + pub fn new( + delegate: BaseKeymapSelectorDelegate, + cx: &mut ViewContext, + ) -> Self { + let picker = cx.build_view(|cx| Picker::new(delegate, cx)); + let focus_handle = cx.focus_handle(); + Self { + focus_handle, + picker, + } + } +} + +impl Render for BaseKeymapSelector { + type Element = View>; + + fn render(&mut self, _cx: &mut ViewContext) -> Self::Element { + self.picker.clone() + } +} pub struct BaseKeymapSelectorDelegate { + view: WeakView, matches: Vec, selected_index: usize, fs: Arc, } impl BaseKeymapSelectorDelegate { - fn new(fs: Arc, cx: &mut ViewContext) -> Self { - let base = settings::get::(cx); + fn new( + weak_view: WeakView, + fs: Arc, + cx: &mut ViewContext, + ) -> Self { + let base = BaseKeymap::get(None, cx); let selected_index = BaseKeymap::OPTIONS .iter() .position(|(_, value)| value == base) .unwrap_or(0); Self { + view: weak_view, matches: Vec::new(), selected_index, fs, @@ -66,16 +109,20 @@ impl PickerDelegate for BaseKeymapSelectorDelegate { self.selected_index } - fn set_selected_index(&mut self, ix: usize, _: &mut ViewContext) { + fn set_selected_index( + &mut self, + ix: usize, + _: &mut ViewContext>, + ) { self.selected_index = ix; } fn update_matches( &mut self, query: String, - cx: &mut ViewContext, + cx: &mut ViewContext>, ) -> Task<()> { - let background = cx.background().clone(); + let background = cx.background_executor().clone(); let candidates = BaseKeymap::names() .enumerate() .map(|(id, name)| StringMatchCandidate { @@ -110,43 +157,44 @@ impl PickerDelegate for BaseKeymapSelectorDelegate { }; this.update(&mut cx, |this, _| { - let delegate = this.delegate_mut(); - delegate.matches = matches; - delegate.selected_index = delegate + this.delegate.matches = matches; + this.delegate.selected_index = this + .delegate .selected_index - .min(delegate.matches.len().saturating_sub(1)); + .min(this.delegate.matches.len().saturating_sub(1)); }) .log_err(); }) } - fn confirm(&mut self, _: bool, cx: &mut ViewContext) { + fn confirm(&mut self, _: bool, cx: &mut ViewContext>) { if let Some(selection) = self.matches.get(self.selected_index) { let base_keymap = BaseKeymap::from_names(&selection.string); update_settings_file::(self.fs.clone(), cx, move |setting| { *setting = Some(base_keymap) }); } - cx.emit(PickerEvent::Dismiss); + + self.view + .update(cx, |_, cx| { + cx.emit(DismissEvent::Dismiss); + }) + .ok(); } - fn dismissed(&mut self, _cx: &mut ViewContext) {} + fn dismissed(&mut self, _cx: &mut ViewContext>) {} fn render_match( &self, ix: usize, - mouse_state: &mut gpui::MouseState, selected: bool, - cx: &gpui::AppContext, - ) -> gpui::AnyElement> { - let theme = &theme::current(cx); + cx: &mut gpui::ViewContext>, + ) -> gpui::AnyElement { let keymap_match = &self.matches[ix]; - let style = theme.picker.item.in_state(selected).style_for(mouse_state); - Label::new(keymap_match.string.clone(), style.label.clone()) - .with_highlights(keymap_match.positions.clone()) - .contained() - .with_style(style.container) - .into_any() + simple_picker_match(selected, cx, |_cx| { + HighlightedLabel::new(keymap_match.string.clone(), keymap_match.positions.clone()) + .into_any_element() + }) } } diff --git a/crates/welcome2/src/base_keymap_setting.rs b/crates/welcome2/src/base_keymap_setting.rs index c5b6171f9b..cad6e894f9 100644 --- a/crates/welcome2/src/base_keymap_setting.rs +++ b/crates/welcome2/src/base_keymap_setting.rs @@ -1,6 +1,6 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use settings::Setting; +use settings::Settings; #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)] pub enum BaseKeymap { @@ -44,7 +44,7 @@ impl BaseKeymap { } } -impl Setting for BaseKeymap { +impl Settings for BaseKeymap { const KEY: Option<&'static str> = Some("base_keymap"); type FileContent = Option; @@ -52,7 +52,7 @@ impl Setting for BaseKeymap { fn load( default_value: &Self::FileContent, user_values: &[&Self::FileContent], - _: &gpui::AppContext, + _: &mut gpui::AppContext, ) -> anyhow::Result where Self: Sized, diff --git a/crates/welcome2/src/welcome.rs b/crates/welcome2/src/welcome.rs index a5d95429bd..68b515f577 100644 --- a/crates/welcome2/src/welcome.rs +++ b/crates/welcome2/src/welcome.rs @@ -1,19 +1,18 @@ mod base_keymap_picker; mod base_keymap_setting; -use crate::base_keymap_picker::ToggleBaseKeymapSelector; -use client::TelemetrySettings; use db::kvp::KEY_VALUE_STORE; use gpui::{ - elements::{Flex, Label, ParentElement}, - AnyElement, AppContext, Element, Entity, Subscription, View, ViewContext, WeakViewHandle, + div, red, AnyElement, AppContext, Div, Element, EventEmitter, FocusHandle, Focusable, + FocusableView, InteractiveElement, ParentElement, Render, Styled, Subscription, View, + ViewContext, VisualContext, WeakView, WindowContext, }; -use settings::{update_settings_file, SettingsStore}; -use std::{borrow::Cow, sync::Arc}; -use vim::VimModeSetting; +use settings::{Settings, SettingsStore}; +use std::sync::Arc; use workspace::{ - dock::DockPosition, item::Item, open_new, AppState, PaneBackdrop, Welcome, Workspace, - WorkspaceId, + dock::DockPosition, + item::{Item, ItemEvent}, + open_new, AppState, Welcome, Workspace, WorkspaceId, }; pub use base_keymap_setting::BaseKeymap; @@ -21,12 +20,15 @@ pub use base_keymap_setting::BaseKeymap; pub const FIRST_OPEN: &str = "first_open"; pub fn init(cx: &mut AppContext) { - settings::register::(cx); + BaseKeymap::register(cx); - cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| { - let welcome_page = cx.add_view(|cx| WelcomePage::new(workspace, cx)); - workspace.add_item(Box::new(welcome_page), cx) - }); + cx.observe_new_views(|workspace: &mut Workspace, _cx| { + workspace.register_action(|workspace, _: &Welcome, cx| { + let welcome_page = cx.build_view(|cx| WelcomePage::new(workspace, cx)); + workspace.add_item(Box::new(welcome_page), cx) + }); + }) + .detach(); base_keymap_picker::init(cx); } @@ -34,9 +36,9 @@ pub fn init(cx: &mut AppContext) { pub fn show_welcome_experience(app_state: &Arc, cx: &mut AppContext) { open_new(&app_state, cx, |workspace, cx| { workspace.toggle_dock(DockPosition::Left, cx); - let welcome_page = cx.add_view(|cx| WelcomePage::new(workspace, cx)); + let welcome_page = cx.build_view(|cx| WelcomePage::new(workspace, cx)); workspace.add_item_to_center(Box::new(welcome_page.clone()), cx); - cx.focus(&welcome_page); + cx.focus_view(&welcome_page); cx.notify(); }) .detach(); @@ -47,227 +49,217 @@ pub fn show_welcome_experience(app_state: &Arc, cx: &mut AppContext) { } pub struct WelcomePage { - workspace: WeakViewHandle, + workspace: WeakView, + focus_handle: FocusHandle, _settings_subscription: Subscription, } -impl Entity for WelcomePage { - type Event = (); -} +impl Render for WelcomePage { + type Element = Focusable
; -impl View for WelcomePage { - fn ui_name() -> &'static str { - "WelcomePage" - } + fn render(&mut self, _cx: &mut gpui::ViewContext) -> Self::Element { + // let self_handle = cx.handle(); + // let theme = cx.theme(); + // let width = theme.welcome.page_width; - fn render(&mut self, cx: &mut gpui::ViewContext) -> AnyElement { - let self_handle = cx.handle(); - let theme = theme::current(cx); - let width = theme.welcome.page_width; + // let telemetry_settings = TelemetrySettings::get(None, cx); + // let vim_mode_setting = VimModeSettings::get(cx); - let telemetry_settings = *settings::get::(cx); - let vim_mode_setting = settings::get::(cx).0; - - enum Metrics {} - enum Diagnostics {} - - PaneBackdrop::new( - self_handle.id(), - Flex::column() - .with_child( - Flex::column() - .with_child( - theme::ui::svg(&theme.welcome.logo) - .aligned() - .contained() - .aligned(), - ) - .with_child( - Label::new( - "Code at the speed of thought", - theme.welcome.logo_subheading.text.clone(), - ) - .aligned() - .contained() - .with_style(theme.welcome.logo_subheading.container), - ) - .contained() - .with_style(theme.welcome.heading_group) - .constrained() - .with_width(width), - ) - .with_child( - Flex::column() - .with_child(theme::ui::cta_button::( - "Choose a theme", - width, - &theme.welcome.button, - cx, - |_, this, cx| { - if let Some(workspace) = this.workspace.upgrade(cx) { - workspace.update(cx, |workspace, cx| { - theme_selector::toggle(workspace, &Default::default(), cx) - }) - } - }, - )) - .with_child(theme::ui::cta_button::( - "Choose a keymap", - width, - &theme.welcome.button, - cx, - |_, this, cx| { - if let Some(workspace) = this.workspace.upgrade(cx) { - workspace.update(cx, |workspace, cx| { - base_keymap_picker::toggle( - workspace, - &Default::default(), - cx, - ) - }) - } - }, - )) - .with_child(theme::ui::cta_button::( - "Install the CLI", - width, - &theme.welcome.button, - cx, - |_, _, cx| { - cx.app_context() - .spawn(|cx| async move { install_cli::install_cli(&cx).await }) - .detach_and_log_err(cx); - }, - )) - .contained() - .with_style(theme.welcome.button_group) - .constrained() - .with_width(width), - ) - .with_child( - Flex::column() - .with_child( - theme::ui::checkbox::( - "Enable vim mode", - &theme.welcome.checkbox, - vim_mode_setting, - 0, - cx, - |this, checked, cx| { - if let Some(workspace) = this.workspace.upgrade(cx) { - let fs = workspace.read(cx).app_state().fs.clone(); - update_settings_file::( - fs, - cx, - move |setting| *setting = Some(checked), - ) - } - }, - ) - .contained() - .with_style(theme.welcome.checkbox_container), - ) - .with_child( - theme::ui::checkbox_with_label::( - Flex::column() - .with_child( - Label::new( - "Send anonymous usage data", - theme.welcome.checkbox.label.text.clone(), - ) - .contained() - .with_style(theme.welcome.checkbox.label.container), - ) - .with_child( - Label::new( - "Help > View Telemetry", - theme.welcome.usage_note.text.clone(), - ) - .contained() - .with_style(theme.welcome.usage_note.container), - ), - &theme.welcome.checkbox, - telemetry_settings.metrics, - 0, - cx, - |this, checked, cx| { - if let Some(workspace) = this.workspace.upgrade(cx) { - let fs = workspace.read(cx).app_state().fs.clone(); - update_settings_file::( - fs, - cx, - move |setting| setting.metrics = Some(checked), - ) - } - }, - ) - .contained() - .with_style(theme.welcome.checkbox_container), - ) - .with_child( - theme::ui::checkbox::( - "Send crash reports", - &theme.welcome.checkbox, - telemetry_settings.diagnostics, - 1, - cx, - |this, checked, cx| { - if let Some(workspace) = this.workspace.upgrade(cx) { - let fs = workspace.read(cx).app_state().fs.clone(); - update_settings_file::( - fs, - cx, - move |setting| setting.diagnostics = Some(checked), - ) - } - }, - ) - .contained() - .with_style(theme.welcome.checkbox_container), - ) - .contained() - .with_style(theme.welcome.checkbox_group) - .constrained() - .with_width(width), - ) - .constrained() - .with_max_width(width) - .contained() - .with_uniform_padding(10.) - .aligned() - .into_any(), - ) - .into_any_named("welcome page") + div() + .track_focus(&self.focus_handle) + .child(div().size_full().bg(red()).child("Welcome!")) + //todo!() + // PaneBackdrop::new( + // self_handle.id(), + // Flex::column() + // .with_child( + // Flex::column() + // .with_child( + // theme::ui::svg(&theme.welcome.logo) + // .aligned() + // .contained() + // .aligned(), + // ) + // .with_child( + // Label::new( + // "Code at the speed of thought", + // theme.welcome.logo_subheading.text.clone(), + // ) + // .aligned() + // .contained() + // .with_style(theme.welcome.logo_subheading.container), + // ) + // .contained() + // .with_style(theme.welcome.heading_group) + // .constrained() + // .with_width(width), + // ) + // .with_child( + // Flex::column() + // .with_child(theme::ui::cta_button::( + // "Choose a theme", + // width, + // &theme.welcome.button, + // cx, + // |_, this, cx| { + // if let Some(workspace) = this.workspace.upgrade(cx) { + // workspace.update(cx, |workspace, cx| { + // theme_selector::toggle(workspace, &Default::default(), cx) + // }) + // } + // }, + // )) + // .with_child(theme::ui::cta_button::( + // "Choose a keymap", + // width, + // &theme.welcome.button, + // cx, + // |_, this, cx| { + // if let Some(workspace) = this.workspace.upgrade(cx) { + // workspace.update(cx, |workspace, cx| { + // base_keymap_picker::toggle( + // workspace, + // &Default::default(), + // cx, + // ) + // }) + // } + // }, + // )) + // .with_child(theme::ui::cta_button::( + // "Install the CLI", + // width, + // &theme.welcome.button, + // cx, + // |_, _, cx| { + // cx.app_context() + // .spawn(|cx| async move { install_cli::install_cli(&cx).await }) + // .detach_and_log_err(cx); + // }, + // )) + // .contained() + // .with_style(theme.welcome.button_group) + // .constrained() + // .with_width(width), + // ) + // .with_child( + // Flex::column() + // .with_child( + // theme::ui::checkbox::( + // "Enable vim mode", + // &theme.welcome.checkbox, + // vim_mode_setting, + // 0, + // cx, + // |this, checked, cx| { + // if let Some(workspace) = this.workspace.upgrade(cx) { + // let fs = workspace.read(cx).app_state().fs.clone(); + // update_settings_file::( + // fs, + // cx, + // move |setting| *setting = Some(checked), + // ) + // } + // }, + // ) + // .contained() + // .with_style(theme.welcome.checkbox_container), + // ) + // .with_child( + // theme::ui::checkbox_with_label::( + // Flex::column() + // .with_child( + // Label::new( + // "Send anonymous usage data", + // theme.welcome.checkbox.label.text.clone(), + // ) + // .contained() + // .with_style(theme.welcome.checkbox.label.container), + // ) + // .with_child( + // Label::new( + // "Help > View Telemetry", + // theme.welcome.usage_note.text.clone(), + // ) + // .contained() + // .with_style(theme.welcome.usage_note.container), + // ), + // &theme.welcome.checkbox, + // telemetry_settings.metrics, + // 0, + // cx, + // |this, checked, cx| { + // if let Some(workspace) = this.workspace.upgrade(cx) { + // let fs = workspace.read(cx).app_state().fs.clone(); + // update_settings_file::( + // fs, + // cx, + // move |setting| setting.metrics = Some(checked), + // ) + // } + // }, + // ) + // .contained() + // .with_style(theme.welcome.checkbox_container), + // ) + // .with_child( + // theme::ui::checkbox::( + // "Send crash reports", + // &theme.welcome.checkbox, + // telemetry_settings.diagnostics, + // 1, + // cx, + // |this, checked, cx| { + // if let Some(workspace) = this.workspace.upgrade(cx) { + // let fs = workspace.read(cx).app_state().fs.clone(); + // update_settings_file::( + // fs, + // cx, + // move |setting| setting.diagnostics = Some(checked), + // ) + // } + // }, + // ) + // .contained() + // .with_style(theme.welcome.checkbox_container), + // ) + // .contained() + // .with_style(theme.welcome.checkbox_group) + // .constrained() + // .with_width(width), + // ) + // .constrained() + // .with_max_width(width) + // .contained() + // .with_uniform_padding(10.) + // .aligned() + // .into_any(), + // ) + // .into_any_named("welcome page") } } impl WelcomePage { pub fn new(workspace: &Workspace, cx: &mut ViewContext) -> Self { WelcomePage { + focus_handle: cx.focus_handle(), workspace: workspace.weak_handle(), - _settings_subscription: cx.observe_global::(move |_, cx| cx.notify()), + _settings_subscription: cx.observe_global::(move |_, cx| cx.notify()), } } } -impl Item for WelcomePage { - fn tab_tooltip_text(&self, _: &AppContext) -> Option> { - Some("Welcome to Zed!".into()) - } +impl EventEmitter for WelcomePage {} - fn tab_content( - &self, - _detail: Option, - style: &theme::Tab, - _cx: &gpui::AppContext, - ) -> AnyElement { - Flex::row() - .with_child( - Label::new("Welcome to Zed!", style.label.clone()) - .aligned() - .contained(), - ) - .into_any() +impl FocusableView for WelcomePage { + fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle { + self.focus_handle.clone() + } +} + +impl Item for WelcomePage { + fn tab_content(&self, _: Option, _: &WindowContext) -> AnyElement { + "Welcome to Zed!".into_any() } fn show_toolbar(&self) -> bool { @@ -278,10 +270,11 @@ impl Item for WelcomePage { &self, _workspace_id: WorkspaceId, cx: &mut ViewContext, - ) -> Option { - Some(WelcomePage { + ) -> Option> { + Some(cx.build_view(|cx| WelcomePage { + focus_handle: cx.focus_handle(), workspace: self.workspace.clone(), - _settings_subscription: cx.observe_global::(move |_, cx| cx.notify()), - }) + _settings_subscription: cx.observe_global::(move |_, cx| cx.notify()), + })) } } diff --git a/crates/workspace2/src/modal_layer.rs b/crates/workspace2/src/modal_layer.rs index 6d28a6299b..6b14151e09 100644 --- a/crates/workspace2/src/modal_layer.rs +++ b/crates/workspace2/src/modal_layer.rs @@ -46,7 +46,6 @@ impl ModalLayer { previous_focus_handle: cx.focused(), focus_handle: cx.focus_handle(), }); - dbg!("focusing"); cx.focus_view(&new_modal); cx.notify(); } diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 50f8611c4c..5d326d3c53 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -1808,22 +1808,22 @@ impl Workspace { pane } - // pub fn add_item_to_center( - // &mut self, - // item: Box, - // cx: &mut ViewContext, - // ) -> bool { - // if let Some(center_pane) = self.last_active_center_pane.clone() { - // if let Some(center_pane) = center_pane.upgrade(cx) { - // center_pane.update(cx, |pane, cx| pane.add_item(item, true, true, None, cx)); - // true - // } else { - // false - // } - // } else { - // false - // } - // } + pub fn add_item_to_center( + &mut self, + item: Box, + cx: &mut ViewContext, + ) -> bool { + if let Some(center_pane) = self.last_active_center_pane.clone() { + if let Some(center_pane) = center_pane.upgrade() { + center_pane.update(cx, |pane, cx| pane.add_item(item, true, true, None, cx)); + true + } else { + false + } + } else { + false + } + } pub fn add_item(&mut self, item: Box, cx: &mut ViewContext) { self.active_pane diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index 843dd00e9f..4d9a61a52f 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -13,7 +13,7 @@ use db::kvp::KEY_VALUE_STORE; use editor::Editor; use fs::RealFs; use futures::StreamExt; -use gpui::{Action, App, AppContext, AsyncAppContext, Context, SemanticVersion, Task}; +use gpui::{App, AppContext, AsyncAppContext, Context, SemanticVersion, Task}; use isahc::{prelude::Configurable, Request}; use language::LanguageRegistry; use log::LevelFilter; @@ -48,6 +48,7 @@ use util::{ paths, ResultExt, }; use uuid::Uuid; +use welcome::{show_welcome_experience, FIRST_OPEN}; use workspace::{AppState, WorkspaceStore}; use zed2::{ build_window_options, ensure_only_instance, handle_cli_connection, initialize_workspace, @@ -163,17 +164,16 @@ fn main() { // assistant::init(cx); // component_test::init(cx); - // cx.spawn(|cx| watch_themes(fs.clone(), cx)).detach(); // cx.spawn(|_| watch_languages(fs.clone(), languages.clone())) // .detach(); // watch_file_types(fs.clone(), cx); languages.set_theme(cx.theme().clone()); - // cx.observe_global::({ - // let languages = languages.clone(); - // move |cx| languages.set_theme(theme::current(cx).clone()) - // }) - // .detach(); + cx.observe_global::({ + let languages = languages.clone(); + move |cx| languages.set_theme(cx.theme().clone()) + }) + .detach(); client.telemetry().start(installation_id, session_id, cx); let telemetry_settings = *client::TelemetrySettings::get_global(cx); @@ -217,14 +217,13 @@ fn main() { // journal2::init(app_state.clone(), cx); // language_selector::init(cx); - // theme_selector::init(cx); + theme_selector::init(cx); // activity_indicator::init(cx); // language_tools::init(cx); call::init(app_state.client.clone(), app_state.user_store.clone(), cx); collab_ui::init(&app_state, cx); // feedback::init(cx); - // welcome::init(cx); - // zed::init(&app_state, cx); + welcome::init(cx); // cx.set_menus(menus::menus()); initialize_workspace(app_state.clone(), cx); @@ -283,6 +282,7 @@ fn main() { cx.spawn(|mut cx| async move { // ignore errors here, we'll show a generic "not signed in" let _ = authenticate(client, &cx).await; + //todo!() // cx.update(|cx| workspace::join_channel(channel_id, app_state, None, cx)) // .await anyhow::Ok(()) @@ -367,7 +367,8 @@ async fn restore_or_create_workspace(app_state: &Arc, mut cx: AsyncApp .await .log_err(); } else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) { - cx.update(|cx| show_welcome_experience(app_state, cx)); + cx.update(|cx| show_welcome_experience(app_state, cx)) + .log_err(); } else { cx.update(|cx| { workspace::open_new(app_state, cx, |workspace, cx| { @@ -705,44 +706,23 @@ fn load_embedded_fonts(cx: &AppContext) { .unwrap(); } -// #[cfg(debug_assertions)] -// async fn watch_themes(fs: Arc, mut cx: AsyncAppContext) -> Option<()> { -// let mut events = fs -// .watch("styles/src".as_ref(), Duration::from_millis(100)) -// .await; -// while (events.next().await).is_some() { -// let output = Command::new("npm") -// .current_dir("styles") -// .args(["run", "build"]) -// .output() -// .await -// .log_err()?; -// if output.status.success() { -// cx.update(|cx| theme_selector::reload(cx)) -// } else { -// eprintln!( -// "build script failed {}", -// String::from_utf8_lossy(&output.stderr) -// ); -// } -// } -// Some(()) -// } +#[cfg(debug_assertions)] +async fn watch_languages(fs: Arc, languages: Arc) -> Option<()> { + use std::time::Duration; -// #[cfg(debug_assertions)] -// async fn watch_languages(fs: Arc, languages: Arc) -> Option<()> { -// let mut events = fs -// .watch( -// "crates/zed/src/languages".as_ref(), -// Duration::from_millis(100), -// ) -// .await; -// while (events.next().await).is_some() { -// languages.reload(); -// } -// Some(()) -// } + let mut events = fs + .watch( + "crates/zed2/src/languages".as_ref(), + Duration::from_millis(100), + ) + .await; + while (events.next().await).is_some() { + languages.reload(); + } + Some(()) +} +//todo!() // #[cfg(debug_assertions)] // fn watch_file_types(fs: Arc, cx: &mut AppContext) { // cx.spawn(|mut cx| async move { @@ -763,26 +743,10 @@ fn load_embedded_fonts(cx: &AppContext) { // .detach() // } -// #[cfg(not(debug_assertions))] -// async fn watch_themes(_fs: Arc, _cx: AsyncAppContext) -> Option<()> { -// None -// } - -// #[cfg(not(debug_assertions))] -// async fn watch_languages(_: Arc, _: Arc) -> Option<()> { -// None -// +#[cfg(not(debug_assertions))] +async fn watch_languages(_: Arc, _: Arc) -> Option<()> { + None +} // #[cfg(not(debug_assertions))] // fn watch_file_types(_fs: Arc, _cx: &mut AppContext) {} - -pub fn background_actions() -> &'static [(&'static str, &'static dyn Action)] { - // &[ - // ("Go to file", &file_finder::Toggle), - // ("Open command palette", &command_palette::Toggle), - // ("Open recent projects", &recent_projects::OpenRecent), - // ("Change your settings", &zed_actions::OpenSettings), - // ] - // todo!() - &[] -}