diff --git a/Cargo.lock b/Cargo.lock index 68919dffbc..7b7acd54f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,7 +182,7 @@ dependencies = [ "alacritty_config", "alacritty_config_derive", "base64 0.13.1", - "bitflags 2.4.0", + "bitflags 2.4.1", "home", "libc", "log", @@ -1025,9 +1025,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" dependencies = [ "serde", ] @@ -3280,6 +3280,7 @@ name = "feedback2" version = "0.1.0" dependencies = [ "anyhow", + "bitflags 2.4.1", "client2", "db2", "editor2", @@ -4026,7 +4027,7 @@ dependencies = [ "async-task", "backtrace", "bindgen 0.65.1", - "bitflags 2.4.0", + "bitflags 2.4.1", "block", "cbindgen", "cocoa", @@ -6195,7 +6196,7 @@ version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if 1.0.0", "foreign-types", "libc", @@ -7915,7 +7916,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -8031,7 +8032,7 @@ version = "0.38.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno 0.3.3", "libc", "linux-raw-sys 0.4.7", @@ -9134,7 +9135,7 @@ dependencies = [ "atoi", "base64 0.21.4", "bigdecimal", - "bitflags 2.4.0", + "bitflags 2.4.1", "byteorder", "bytes 1.5.0", "chrono", @@ -9181,7 +9182,7 @@ dependencies = [ "atoi", "base64 0.21.4", "bigdecimal", - "bitflags 2.4.0", + "bitflags 2.4.1", "byteorder", "chrono", "crc", diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index 298c7682eb..65a994e6d9 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -2552,12 +2552,11 @@ impl CollabPanel { .group("") .flex() .w_full() - .on_drag({ - let channel = channel.clone(); - move |cx| { - let channel = channel.clone(); - cx.build_view(|cx| DraggedChannelView { channel, width }) - } + .on_drag(channel.clone(), move |channel, cx| { + cx.build_view(|cx| DraggedChannelView { + channel: channel.clone(), + width, + }) }) .drag_over::(|style| { style.bg(cx.theme().colors().ghost_element_hover) diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 89b5fd2efb..e58aa1000d 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -9297,7 +9297,7 @@ impl Render for Editor { let settings = ThemeSettings::get_global(cx); let text_style = match self.mode { EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle { - color: cx.theme().colors().text, + color: cx.theme().colors().editor_foreground, font_family: settings.ui_font.family.clone(), font_features: settings.ui_font.features, font_size: rems(0.875).into(), @@ -9310,7 +9310,7 @@ impl Render for Editor { }, EditorMode::Full => TextStyle { - color: cx.theme().colors().text, + color: cx.theme().colors().editor_foreground, font_family: settings.buffer_font.family.clone(), font_features: settings.buffer_font.features, font_size: settings.buffer_font_size(cx).into(), diff --git a/crates/feedback2/Cargo.toml b/crates/feedback2/Cargo.toml index 0e34ee410b..9fe125ec57 100644 --- a/crates/feedback2/Cargo.toml +++ b/crates/feedback2/Cargo.toml @@ -18,7 +18,6 @@ gpui = { package = "gpui2", path = "../gpui2" } language = { package = "language2", path = "../language2" } menu = { package = "menu2", path = "../menu2" } project = { package = "project2", path = "../project2" } -regex.workspace = true search = { package = "search2", path = "../search2" } settings = { package = "settings2", path = "../settings2" } theme = { package = "theme2", path = "../theme2" } @@ -26,13 +25,16 @@ ui = { package = "ui2", path = "../ui2" } util = { path = "../util" } workspace = { package = "workspace2", path = "../workspace2"} +bitflags = "2.4.1" +human_bytes = "0.4.1" + anyhow.workspace = true futures.workspace = true -human_bytes = "0.4.1" isahc.workspace = true lazy_static.workspace = true log.workspace = true postage.workspace = true +regex.workspace = true serde.workspace = true serde_derive.workspace = true smallvec.workspace = true diff --git a/crates/feedback2/src/feedback_modal.rs b/crates/feedback2/src/feedback_modal.rs index 3130c4bad6..22904f3a0a 100644 --- a/crates/feedback2/src/feedback_modal.rs +++ b/crates/feedback2/src/feedback_modal.rs @@ -1,6 +1,7 @@ use std::{ops::RangeInclusive, sync::Arc, time::Duration}; use anyhow::{anyhow, bail}; +use bitflags::bitflags; use client::{Client, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL}; use db::kvp::KEY_VALUE_STORE; use editor::{Editor, EditorEvent}; @@ -48,15 +49,17 @@ struct FeedbackRequestBody<'a> { token: &'a str, } -#[derive(Debug, Clone, PartialEq)] -enum InvalidStateIssue { - EmailAddress, - CharacterCount, +bitflags! { + #[derive(Debug, Clone, PartialEq)] + struct InvalidStateFlags: u8 { + const EmailAddress = 0b00000001; + const CharacterCount = 0b00000010; + } } #[derive(Debug, Clone, PartialEq)] enum CannotSubmitReason { - InvalidState { issues: Vec }, + InvalidState { flags: InvalidStateFlags }, AwaitingSubmission, } @@ -322,7 +325,7 @@ impl FeedbackModal { return; } - let mut invalid_state_issues = Vec::new(); + let mut invalid_state_flags = InvalidStateFlags::empty(); let valid_email_address = match self.email_address_editor.read(cx).text_option(cx) { Some(email_address) => Regex::new(EMAIL_REGEX).unwrap().is_match(&email_address), @@ -330,37 +333,37 @@ impl FeedbackModal { }; if !valid_email_address { - invalid_state_issues.push(InvalidStateIssue::EmailAddress); + invalid_state_flags |= InvalidStateFlags::EmailAddress; } if !FEEDBACK_CHAR_LIMIT.contains(&self.character_count) { - invalid_state_issues.push(InvalidStateIssue::CharacterCount); + invalid_state_flags |= InvalidStateFlags::CharacterCount; } - if invalid_state_issues.is_empty() { + if invalid_state_flags.is_empty() { self.submission_state = Some(SubmissionState::CanSubmit); } else { self.submission_state = Some(SubmissionState::CannotSubmit { reason: CannotSubmitReason::InvalidState { - issues: invalid_state_issues, + flags: invalid_state_flags, }, }); } } fn valid_email_address(&self) -> bool { - !self.in_invalid_state(InvalidStateIssue::EmailAddress) + !self.in_invalid_state(InvalidStateFlags::EmailAddress) } fn valid_character_count(&self) -> bool { - !self.in_invalid_state(InvalidStateIssue::CharacterCount) + !self.in_invalid_state(InvalidStateFlags::CharacterCount) } - fn in_invalid_state(&self, a: InvalidStateIssue) -> bool { + fn in_invalid_state(&self, flag: InvalidStateFlags) -> bool { match self.submission_state { Some(SubmissionState::CannotSubmit { - reason: CannotSubmitReason::InvalidState { ref issues }, - }) => issues.contains(&a), + reason: CannotSubmitReason::InvalidState { ref flags }, + }) => flags.contains(flag), _ => false, } } diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 18f688f179..bfbdc6b4a6 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -1139,8 +1139,10 @@ impl AppContext { self.active_drag.is_some() } - pub fn active_drag(&self) -> Option { - self.active_drag.as_ref().map(|drag| drag.view.clone()) + pub fn active_drag(&self) -> Option<&T> { + self.active_drag + .as_ref() + .and_then(|drag| drag.value.downcast_ref()) } } @@ -1296,6 +1298,7 @@ impl DerefMut for GlobalLease { /// within the window or by dragging into the app from the underlying platform. pub struct AnyDrag { pub view: AnyView, + pub value: Box, pub cursor_offset: Point, } diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index ff2e87e8e7..61501d7a69 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -15,6 +15,7 @@ use std::{ cell::RefCell, cmp::Ordering, fmt::Debug, + marker::PhantomData, mem, rc::Rc, time::Duration, @@ -30,9 +31,18 @@ pub struct GroupStyle { pub style: Box, } -pub struct DragMoveEvent { +pub struct DragMoveEvent { pub event: MouseMoveEvent, - pub drag: View, + drag: PhantomData, +} + +impl DragMoveEvent { + pub fn drag<'b>(&self, cx: &'b AppContext) -> &'b T { + cx.active_drag + .as_ref() + .and_then(|drag| drag.value.downcast_ref::()) + .expect("DragMoveEvent is only valid when the stored active drag is of the same type.") + } } impl Interactivity { @@ -133,23 +143,26 @@ impl Interactivity { })); } - pub fn on_drag_move( + pub fn on_drag_move( &mut self, - listener: impl Fn(&DragMoveEvent, &mut WindowContext) + 'static, + listener: impl Fn(&DragMoveEvent, &mut WindowContext) + 'static, ) where - W: Render, + T: 'static, { self.mouse_move_listeners .push(Box::new(move |event, bounds, phase, cx| { if phase == DispatchPhase::Capture && bounds.drag_target_contains(&event.position, cx) { - if let Some(view) = cx.active_drag().and_then(|view| view.downcast::().ok()) + if cx + .active_drag + .as_ref() + .is_some_and(|drag| drag.value.type_id() == TypeId::of::()) { (listener)( &DragMoveEvent { event: event.clone(), - drag: view, + drag: PhantomData, }, cx, ); @@ -252,14 +265,11 @@ impl Interactivity { })); } - pub fn on_drop( - &mut self, - listener: impl Fn(&View, &mut WindowContext) + 'static, - ) { + pub fn on_drop(&mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) { self.drop_listeners.push(( - TypeId::of::(), - Box::new(move |dragged_view, cx| { - listener(&dragged_view.downcast().unwrap(), cx); + TypeId::of::(), + Box::new(move |dragged_value, cx| { + listener(dragged_value.downcast_ref().unwrap(), cx); }), )); } @@ -272,19 +282,23 @@ impl Interactivity { .push(Box::new(move |event, cx| listener(event, cx))); } - pub fn on_drag(&mut self, constructor: impl Fn(&mut WindowContext) -> View + 'static) - where + pub fn on_drag( + &mut self, + value: T, + constructor: impl Fn(&T, &mut WindowContext) -> View + 'static, + ) where Self: Sized, + T: 'static, W: 'static + Render, { debug_assert!( self.drag_listener.is_none(), "calling on_drag more than once on the same element is not supported" ); - self.drag_listener = Some(Box::new(move |cursor_offset, cx| AnyDrag { - view: constructor(cx).into(), - cursor_offset, - })); + self.drag_listener = Some(( + Box::new(value), + Box::new(move |value, cx| constructor(value.downcast_ref().unwrap(), cx).into()), + )); } pub fn on_hover(&mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static) @@ -413,12 +427,12 @@ pub trait InteractiveElement: Sized { self } - fn on_drag_move( + fn on_drag_move( mut self, - listener: impl Fn(&DragMoveEvent, &mut WindowContext) + 'static, + listener: impl Fn(&DragMoveEvent, &mut WindowContext) + 'static, ) -> Self where - W: Render, + T: Render, { self.interactivity().on_drag_move(listener); self @@ -485,14 +499,6 @@ pub trait InteractiveElement: Sized { self } - fn on_drop( - mut self, - listener: impl Fn(&View, &mut WindowContext) + 'static, - ) -> Self { - self.interactivity().on_drop(listener); - self - } - fn drag_over(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self { self.interactivity() .drag_over_styles @@ -514,6 +520,11 @@ pub trait InteractiveElement: Sized { )); self } + + fn on_drop(mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) -> Self { + self.interactivity().on_drop(listener); + self + } } pub trait StatefulInteractiveElement: InteractiveElement { @@ -574,12 +585,17 @@ pub trait StatefulInteractiveElement: InteractiveElement { self } - fn on_drag(mut self, constructor: impl Fn(&mut WindowContext) -> View + 'static) -> Self + fn on_drag( + mut self, + value: T, + constructor: impl Fn(&T, &mut WindowContext) -> View + 'static, + ) -> Self where Self: Sized, + T: 'static, W: 'static + Render, { - self.interactivity().on_drag(constructor); + self.interactivity().on_drag(value, constructor); self } @@ -635,9 +651,9 @@ pub type ScrollWheelListener = pub type ClickListener = Box; -pub type DragListener = Box, &mut WindowContext) -> AnyDrag + 'static>; +pub type DragListener = Box AnyView + 'static>; -type DropListener = dyn Fn(AnyView, &mut WindowContext) + 'static; +type DropListener = Box; pub type TooltipBuilder = Rc AnyView + 'static>; @@ -834,9 +850,9 @@ pub struct Interactivity { pub key_down_listeners: Vec, pub key_up_listeners: Vec, pub action_listeners: Vec<(TypeId, ActionListener)>, - pub drop_listeners: Vec<(TypeId, Box)>, + pub drop_listeners: Vec<(TypeId, DropListener)>, pub click_listeners: Vec, - pub drag_listener: Option, + pub drag_listener: Option<(Box, DragListener)>, pub hover_listener: Option>, pub tooltip_builder: Option, @@ -1124,8 +1140,10 @@ impl Interactivity { if phase == DispatchPhase::Bubble && interactive_bounds.drag_target_contains(&event.position, cx) { - if let Some(drag_state_type) = - cx.active_drag.as_ref().map(|drag| drag.view.entity_type()) + if let Some(drag_state_type) = cx + .active_drag + .as_ref() + .map(|drag| drag.value.as_ref().type_id()) { for (drop_state_type, listener) in &drop_listeners { if *drop_state_type == drag_state_type { @@ -1134,7 +1152,7 @@ impl Interactivity { .take() .expect("checked for type drag state type above"); - listener(drag.view.clone(), cx); + listener(drag.value.as_ref(), cx); cx.notify(); cx.stop_propagation(); } @@ -1148,7 +1166,7 @@ impl Interactivity { } let click_listeners = mem::take(&mut self.click_listeners); - let drag_listener = mem::take(&mut self.drag_listener); + let mut drag_listener = mem::take(&mut self.drag_listener); if !click_listeners.is_empty() || drag_listener.is_some() { let pending_mouse_down = element_state @@ -1157,7 +1175,7 @@ impl Interactivity { .clone(); let mouse_down = pending_mouse_down.borrow().clone(); if let Some(mouse_down) = mouse_down { - if let Some(drag_listener) = drag_listener { + if drag_listener.is_some() { let active_state = element_state .clicked_state .get_or_insert_with(Default::default) @@ -1173,10 +1191,18 @@ impl Interactivity { && interactive_bounds.visibly_contains(&event.position, cx) && (event.position - mouse_down.position).magnitude() > DRAG_THRESHOLD { + let (drag_value, drag_listener) = drag_listener + .take() + .expect("The notify below should invalidate this callback"); + *active_state.borrow_mut() = ElementClickedState::default(); let cursor_offset = event.position - bounds.origin; - let drag = drag_listener(cursor_offset, cx); - cx.active_drag = Some(drag); + let drag = (drag_listener)(drag_value.as_ref(), cx); + cx.active_drag = Some(AnyDrag { + view: drag, + value: drag_value, + cursor_offset, + }); cx.notify(); cx.stop_propagation(); } @@ -1470,7 +1496,7 @@ impl Interactivity { if let Some(drag) = cx.active_drag.take() { for (state_type, group_drag_style) in &self.group_drag_over_styles { if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) { - if *state_type == drag.view.entity_type() + if *state_type == drag.value.as_ref().type_id() && group_bounds.contains(&mouse_position) { style.refine(&group_drag_style.style); @@ -1479,7 +1505,7 @@ impl Interactivity { } for (state_type, drag_over_style) in &self.drag_over_styles { - if *state_type == drag.view.entity_type() + if *state_type == drag.value.as_ref().type_id() && bounds .intersect(&cx.content_mask().bounds) .contains(&mouse_position) diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index 7657ae2512..fb61190731 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -7,6 +7,7 @@ use crate::{ use anyhow::{Context, Result}; use std::{ any::TypeId, + fmt, hash::{Hash, Hasher}, }; @@ -308,6 +309,20 @@ impl From> for AnyWeakView { } } +impl PartialEq for AnyWeakView { + fn eq(&self, other: &Self) -> bool { + self.model == other.model + } +} + +impl std::fmt::Debug for AnyWeakView { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AnyWeakView") + .field("entity_id", &self.model.entity_id) + .finish_non_exhaustive() + } +} + impl Render for T where T: 'static + FnMut(&mut WindowContext) -> E, diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 2b00d193d6..daa43804b0 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -822,7 +822,7 @@ impl<'a> WindowContext<'a> { /// a specific need to register a global listener. pub fn on_mouse_event( &mut self, - handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + 'static, + mut handler: impl FnMut(&Event, DispatchPhase, &mut WindowContext) + 'static, ) { let order = self.window.next_frame.z_index_stack.clone(); self.window @@ -1400,6 +1400,7 @@ impl<'a> WindowContext<'a> { self.window.mouse_position = position; if self.active_drag.is_none() { self.active_drag = Some(AnyDrag { + value: Box::new(files.clone()), view: self.build_view(|_| files).into(), cursor_offset: position, }); diff --git a/crates/project_panel2/src/project_panel.rs b/crates/project_panel2/src/project_panel.rs index adcd21cac6..417b351df7 100644 --- a/crates/project_panel2/src/project_panel.rs +++ b/crates/project_panel2/src/project_panel.rs @@ -1377,33 +1377,28 @@ impl ProjectPanel { }) .unwrap_or(theme.status().info); + let file_name = details.filename.clone(); + let icon = details.icon.clone(); + let depth = details.depth; div() .id(entry_id.to_proto() as usize) - .on_drag({ - let details = details.clone(); - move |cx| { - let details = details.clone(); - cx.build_view(|_| DraggedProjectEntryView { - details, - width, - entry_id, - }) - } + .on_drag(entry_id, move |entry_id, cx| { + cx.build_view(|_| DraggedProjectEntryView { + details: details.clone(), + width, + entry_id: *entry_id, + }) }) - .drag_over::(|style| { - style.bg(cx.theme().colors().ghost_element_hover) - }) - .on_drop(cx.listener( - move |this, dragged_view: &View, cx| { - this.move_entry(dragged_view.read(cx).entry_id, entry_id, kind.is_file(), cx); - }, - )) + .drag_over::(|style| style.bg(cx.theme().colors().ghost_element_hover)) + .on_drop(cx.listener(move |this, dragged_id: &ProjectEntryId, cx| { + this.move_entry(*dragged_id, entry_id, kind.is_file(), cx); + })) .child( ListItem::new(entry_id.to_proto() as usize) - .indent_level(details.depth) + .indent_level(depth) .indent_step_size(px(settings.indent_size)) .selected(is_selected) - .child(if let Some(icon) = &details.icon { + .child(if let Some(icon) = &icon { div().child(IconElement::from_path(icon.to_string())) } else { div() @@ -1414,7 +1409,7 @@ impl ProjectPanel { } else { div() .text_color(filename_text_color) - .child(Label::new(details.filename.clone())) + .child(Label::new(file_name)) } .ml_1(), ) diff --git a/crates/search2/src/project_search.rs b/crates/search2/src/project_search.rs index bedbc25b22..ef7d7fe70d 100644 --- a/crates/search2/src/project_search.rs +++ b/crates/search2/src/project_search.rs @@ -1590,12 +1590,16 @@ impl Render for ProjectSearchBar { ); let replace_column = if search.replace_enabled { h_stack() - .p_1() .flex_1() - .border_2() + .h_full() + .gap_2() + .px_2() + .py_1() + .border_1() + .border_color(cx.theme().colors().border) .rounded_lg() .child(IconElement::new(Icon::Replace).size(ui::IconSize::Small)) - .child(search.replacement_editor.clone()) + .child(self.render_text_input(&search.replacement_editor, cx)) } else { // Fill out the space if we don't have a replacement editor. h_stack().flex_1() @@ -1658,10 +1662,10 @@ impl Render for ProjectSearchBar { ]); v_stack() .key_context(key_context) + .flex_grow() .p_1() .m_2() .gap_2() - .justify_between() .on_action(cx.listener(|this, _: &ToggleFilters, cx| { this.toggle_filters(cx); })) @@ -1713,10 +1717,59 @@ impl Render for ProjectSearchBar { })) }) }) - .child(query_column) - .child(mode_column) - .child(replace_column) - .child(actions_column) + .child( + h_stack() + .justify_between() + .child(query_column) + .child(mode_column) + .child(replace_column) + .child(actions_column), + ) + .when(search.filters_enabled, |this| { + this.child( + h_stack() + .flex_1() + .gap_2() + .justify_between() + .child( + h_stack() + .flex_1() + .h_full() + .px_2() + .py_1() + .border_1() + .border_color(cx.theme().colors().border) + .rounded_lg() + .child(self.render_text_input(&search.included_files_editor, cx)) + .when(search.current_mode != SearchMode::Semantic, |this| { + this.child( + SearchOptions::INCLUDE_IGNORED.as_button( + search + .search_options + .contains(SearchOptions::INCLUDE_IGNORED), + cx.listener(|this, _, cx| { + this.toggle_search_option( + SearchOptions::INCLUDE_IGNORED, + cx, + ); + }), + ), + ) + }), + ) + .child( + h_stack() + .flex_1() + .h_full() + .px_2() + .py_1() + .border_1() + .border_color(cx.theme().colors().border) + .rounded_lg() + .child(self.render_text_input(&search.excluded_files_editor, cx)), + ), + ) + }) } } // impl Entity for ProjectSearchBar { diff --git a/crates/terminal_view2/src/terminal_element.rs b/crates/terminal_view2/src/terminal_element.rs index 7f221129f0..e9335a4220 100644 --- a/crates/terminal_view2/src/terminal_element.rs +++ b/crates/terminal_view2/src/terminal_element.rs @@ -695,7 +695,6 @@ impl TerminalElement { move |external_paths, cx| { cx.focus(&focus); let mut new_text = external_paths - .read(cx) .paths() .iter() .map(|path| format!(" {path:?}")) diff --git a/crates/theme2/src/themes/andromeda.rs b/crates/theme2/src/themes/andromeda.rs index 33284cdbee..32bccf172a 100644 --- a/crates/theme2/src/themes/andromeda.rs +++ b/crates/theme2/src/themes/andromeda.rs @@ -47,6 +47,7 @@ pub fn andromeda() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x3a3f4c77).into()), scrollbar_track_background: Some(rgba(0x23262eff).into()), scrollbar_track_border: Some(rgba(0x1b1d23ff).into()), + editor_foreground: Some(rgba(0xd5ced9ff).into()), editor_background: Some(rgba(0x23262eff).into()), editor_gutter_background: Some(rgba(0x23262eff).into()), editor_line_number: Some(rgba(0x746f77ff).into()), @@ -261,6 +262,7 @@ pub fn andromeda() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x3a3f4c77).into()), scrollbar_track_background: Some(rgba(0x262a33ff).into()), scrollbar_track_border: Some(rgba(0x1b1d23ff).into()), + editor_foreground: Some(rgba(0xd5ced9ff).into()), editor_background: Some(rgba(0x262a33ff).into()), editor_gutter_background: Some(rgba(0x262a33ff).into()), editor_line_number: Some(rgba(0x746f77ff).into()), diff --git a/crates/theme2/src/themes/ayu.rs b/crates/theme2/src/themes/ayu.rs index 0164e4786f..4c5d951230 100644 --- a/crates/theme2/src/themes/ayu.rs +++ b/crates/theme2/src/themes/ayu.rs @@ -46,6 +46,7 @@ pub fn ayu() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x8a919966).into()), scrollbar_track_background: Some(rgba(0xf8f9faff).into()), scrollbar_track_border: Some(rgba(0x6b7d8f1f).into()), + editor_foreground: Some(rgba(0x5c6166ff).into()), editor_background: Some(rgba(0xf8f9faff).into()), editor_gutter_background: Some(rgba(0xf8f9faff).into()), editor_line_number: Some(rgba(0x8a919966).into()), @@ -352,6 +353,7 @@ pub fn ayu() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x707a8c66).into()), scrollbar_track_background: Some(rgba(0x1f2430ff).into()), scrollbar_track_border: Some(rgba(0x171b24ff).into()), + editor_foreground: Some(rgba(0xcccac2ff).into()), editor_background: Some(rgba(0x1f2430ff).into()), editor_gutter_background: Some(rgba(0x1f2430ff).into()), editor_line_number: Some(rgba(0x8a919966).into()), @@ -658,6 +660,7 @@ pub fn ayu() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x565b6666).into()), scrollbar_track_background: Some(rgba(0x0b0e14ff).into()), scrollbar_track_border: Some(rgba(0x1e232bff).into()), + editor_foreground: Some(rgba(0xbfbdb6ff).into()), editor_background: Some(rgba(0x0b0e14ff).into()), editor_gutter_background: Some(rgba(0x0b0e14ff).into()), editor_line_number: Some(rgba(0x6c738099).into()), diff --git a/crates/theme2/src/themes/dracula.rs b/crates/theme2/src/themes/dracula.rs index 5933ec46ff..3fabb67ec2 100644 --- a/crates/theme2/src/themes/dracula.rs +++ b/crates/theme2/src/themes/dracula.rs @@ -43,6 +43,7 @@ pub fn dracula() -> UserThemeFamily { tab_active_background: Some(rgba(0x282a36ff).into()), scrollbar_track_background: Some(rgba(0x282a36ff).into()), scrollbar_track_border: Some(rgba(0x191a21ff).into()), + editor_foreground: Some(rgba(0xf8f8f2ff).into()), editor_background: Some(rgba(0x282a36ff).into()), editor_gutter_background: Some(rgba(0x282a36ff).into()), editor_line_number: Some(rgba(0x6272a4ff).into()), diff --git a/crates/theme2/src/themes/gruvbox.rs b/crates/theme2/src/themes/gruvbox.rs index 4573f55ca1..2c96665534 100644 --- a/crates/theme2/src/themes/gruvbox.rs +++ b/crates/theme2/src/themes/gruvbox.rs @@ -46,6 +46,7 @@ pub fn gruvbox() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x50494599).into()), scrollbar_track_background: Some(rgba(0x1d2021ff).into()), scrollbar_track_border: Some(rgba(0x1d202100).into()), + editor_foreground: Some(rgba(0xebdbb2ff).into()), editor_background: Some(rgba(0x1d2021ff).into()), editor_gutter_background: Some(rgba(0x1d2021ff).into()), editor_line_number: Some(rgba(0x665c54ff).into()), @@ -338,6 +339,7 @@ pub fn gruvbox() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x50494599).into()), scrollbar_track_background: Some(rgba(0x282828ff).into()), scrollbar_track_border: Some(rgba(0x28282800).into()), + editor_foreground: Some(rgba(0xebdbb2ff).into()), editor_background: Some(rgba(0x282828ff).into()), editor_gutter_background: Some(rgba(0x282828ff).into()), editor_line_number: Some(rgba(0x665c54ff).into()), @@ -630,6 +632,7 @@ pub fn gruvbox() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x50494599).into()), scrollbar_track_background: Some(rgba(0x32302fff).into()), scrollbar_track_border: Some(rgba(0x32302f00).into()), + editor_foreground: Some(rgba(0xebdbb2ff).into()), editor_background: Some(rgba(0x32302fff).into()), editor_gutter_background: Some(rgba(0x32302fff).into()), editor_line_number: Some(rgba(0x665c54ff).into()), @@ -922,6 +925,7 @@ pub fn gruvbox() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0xd5c4a199).into()), scrollbar_track_background: Some(rgba(0xf9f5d7ff).into()), scrollbar_track_border: Some(rgba(0xf9f5d700).into()), + editor_foreground: Some(rgba(0x3c3836ff).into()), editor_background: Some(rgba(0xf9f5d7ff).into()), editor_gutter_background: Some(rgba(0xf9f5d7ff).into()), editor_line_number: Some(rgba(0xbdae93ff).into()), @@ -1214,6 +1218,7 @@ pub fn gruvbox() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0xd5c4a199).into()), scrollbar_track_background: Some(rgba(0xfbf1c7ff).into()), scrollbar_track_border: Some(rgba(0xfbf1c700).into()), + editor_foreground: Some(rgba(0x3c3836ff).into()), editor_background: Some(rgba(0xfbf1c7ff).into()), editor_gutter_background: Some(rgba(0xfbf1c7ff).into()), editor_line_number: Some(rgba(0xbdae93ff).into()), @@ -1506,6 +1511,7 @@ pub fn gruvbox() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0xd5c4a199).into()), scrollbar_track_background: Some(rgba(0xf2e5bcff).into()), scrollbar_track_border: Some(rgba(0xf2e5bc00).into()), + editor_foreground: Some(rgba(0x3c3836ff).into()), editor_background: Some(rgba(0xf2e5bcff).into()), editor_gutter_background: Some(rgba(0xf2e5bcff).into()), editor_line_number: Some(rgba(0xbdae93ff).into()), diff --git a/crates/theme2/src/themes/night_owl.rs b/crates/theme2/src/themes/night_owl.rs index 71c980e631..778dfabeb8 100644 --- a/crates/theme2/src/themes/night_owl.rs +++ b/crates/theme2/src/themes/night_owl.rs @@ -46,6 +46,7 @@ pub fn night_owl() -> UserThemeFamily { scrollbar_thumb_hover_background: Some(rgba(0x084d8180).into()), scrollbar_thumb_border: Some(rgba(0x084d8180).into()), scrollbar_track_background: Some(rgba(0x011627ff).into()), + editor_foreground: Some(rgba(0xd6deebff).into()), editor_background: Some(rgba(0x011627ff).into()), editor_gutter_background: Some(rgba(0x011627ff).into()), editor_line_number: Some(rgba(0x4b6479ff).into()), @@ -305,6 +306,7 @@ pub fn night_owl() -> UserThemeFamily { tab_inactive_background: Some(rgba(0xf0f0f0ff).into()), tab_active_background: Some(rgba(0xf6f6f6ff).into()), scrollbar_track_background: Some(rgba(0xfbfbfbff).into()), + editor_foreground: Some(rgba(0x403f53ff).into()), editor_background: Some(rgba(0xfbfbfbff).into()), editor_gutter_background: Some(rgba(0xfbfbfbff).into()), editor_line_number: Some(rgba(0x90a7b2ff).into()), diff --git a/crates/theme2/src/themes/noctis.rs b/crates/theme2/src/themes/noctis.rs index 51b442a57e..614553593d 100644 --- a/crates/theme2/src/themes/noctis.rs +++ b/crates/theme2/src/themes/noctis.rs @@ -47,6 +47,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x008ee633).into()), scrollbar_track_background: Some(rgba(0x07273bff).into()), scrollbar_track_border: Some(rgba(0x07273bff).into()), + editor_foreground: Some(rgba(0xbecfdaff).into()), editor_background: Some(rgba(0x07273bff).into()), editor_gutter_background: Some(rgba(0x07273bff).into()), editor_line_number: Some(rgba(0x4d6c80ff).into()), @@ -324,6 +325,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0xeb609133).into()), scrollbar_track_background: Some(rgba(0x322a2dff).into()), scrollbar_track_border: Some(rgba(0x322a2dff).into()), + editor_foreground: Some(rgba(0xcbbec2ff).into()), editor_background: Some(rgba(0x322a2dff).into()), editor_gutter_background: Some(rgba(0x322a2dff).into()), editor_line_number: Some(rgba(0x715b63ff).into()), @@ -601,6 +603,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_track_background: Some(rgba(0xf4f6f6ff).into()), scrollbar_track_border: Some(rgba(0xf4f6f6ff).into()), + editor_foreground: Some(rgba(0x005661ff).into()), editor_background: Some(rgba(0xf4f6f6ff).into()), editor_gutter_background: Some(rgba(0xf4f6f6ff).into()), editor_line_number: Some(rgba(0xa0abacff).into()), @@ -878,6 +881,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_track_background: Some(rgba(0xf2f1f8ff).into()), scrollbar_track_border: Some(rgba(0xf2f1f8ff).into()), + editor_foreground: Some(rgba(0x0c006bff).into()), editor_background: Some(rgba(0xf2f1f8ff).into()), editor_gutter_background: Some(rgba(0xf2f1f8ff).into()), editor_line_number: Some(rgba(0x9d9ab1ff).into()), @@ -1155,6 +1159,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_track_background: Some(rgba(0xfef8ecff).into()), scrollbar_track_border: Some(rgba(0xfef8ecff).into()), + editor_foreground: Some(rgba(0x005661ff).into()), editor_background: Some(rgba(0xfef8ecff).into()), editor_gutter_background: Some(rgba(0xfef8ecff).into()), editor_line_number: Some(rgba(0xa0abacff).into()), @@ -1432,6 +1437,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x3f7fa633).into()), scrollbar_track_background: Some(rgba(0x1b2932ff).into()), scrollbar_track_border: Some(rgba(0x1b2932ff).into()), + editor_foreground: Some(rgba(0xc5cdd3ff).into()), editor_background: Some(rgba(0x1b2932ff).into()), editor_gutter_background: Some(rgba(0x1b2932ff).into()), editor_line_number: Some(rgba(0x5d6e79ff).into()), @@ -1709,6 +1715,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_track_background: Some(rgba(0x052529ff).into()), scrollbar_track_border: Some(rgba(0x052529ff).into()), + editor_foreground: Some(rgba(0xb2cacdff).into()), editor_background: Some(rgba(0x052529ff).into()), editor_gutter_background: Some(rgba(0x052529ff).into()), editor_line_number: Some(rgba(0x4e6b6eff).into()), @@ -1986,6 +1993,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_track_background: Some(rgba(0x031417ff).into()), scrollbar_track_border: Some(rgba(0x031417ff).into()), + editor_foreground: Some(rgba(0xb2cacdff).into()), editor_background: Some(rgba(0x031417ff).into()), editor_gutter_background: Some(rgba(0x031417ff).into()), editor_line_number: Some(rgba(0x4e6b6eff).into()), @@ -2263,6 +2271,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_track_background: Some(rgba(0x031417ff).into()), scrollbar_track_border: Some(rgba(0x031417ff).into()), + editor_foreground: Some(rgba(0xb2cacdff).into()), editor_background: Some(rgba(0x031417ff).into()), editor_gutter_background: Some(rgba(0x031417ff).into()), editor_line_number: Some(rgba(0x4e6b6eff).into()), @@ -2540,6 +2549,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x7060eb33).into()), scrollbar_track_background: Some(rgba(0x292640ff).into()), scrollbar_track_border: Some(rgba(0x292640ff).into()), + editor_foreground: Some(rgba(0xc5c2d6ff).into()), editor_background: Some(rgba(0x292640ff).into()), editor_gutter_background: Some(rgba(0x292640ff).into()), editor_line_number: Some(rgba(0x5c5973ff).into()), @@ -2817,6 +2827,7 @@ pub fn noctis() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0xa660eb33).into()), scrollbar_track_background: Some(rgba(0x30243dff).into()), scrollbar_track_border: Some(rgba(0x30243dff).into()), + editor_foreground: Some(rgba(0xccbfd9ff).into()), editor_background: Some(rgba(0x30243dff).into()), editor_gutter_background: Some(rgba(0x30243dff).into()), editor_line_number: Some(rgba(0x665973ff).into()), diff --git a/crates/theme2/src/themes/nord.rs b/crates/theme2/src/themes/nord.rs index 949926c685..f3d03b3889 100644 --- a/crates/theme2/src/themes/nord.rs +++ b/crates/theme2/src/themes/nord.rs @@ -46,6 +46,7 @@ pub fn nord() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x434c5e99).into()), scrollbar_track_background: Some(rgba(0x2e3440ff).into()), scrollbar_track_border: Some(rgba(0x3b4252ff).into()), + editor_foreground: Some(rgba(0xd8dee9ff).into()), editor_background: Some(rgba(0x2e3440ff).into()), editor_gutter_background: Some(rgba(0x2e3440ff).into()), editor_line_number: Some(rgba(0x4c566aff).into()), diff --git a/crates/theme2/src/themes/palenight.rs b/crates/theme2/src/themes/palenight.rs index ab47cc1046..501a678577 100644 --- a/crates/theme2/src/themes/palenight.rs +++ b/crates/theme2/src/themes/palenight.rs @@ -46,6 +46,7 @@ pub fn palenight() -> UserThemeFamily { scrollbar_thumb_hover_background: Some(rgba(0x694ca4cc).into()), scrollbar_thumb_border: Some(rgba(0x694ca466).into()), scrollbar_track_background: Some(rgba(0x292d3eff).into()), + editor_foreground: Some(rgba(0xbfc7d5ff).into()), editor_background: Some(rgba(0x292d3eff).into()), editor_gutter_background: Some(rgba(0x292d3eff).into()), editor_line_number: Some(rgba(0x4c5374ff).into()), @@ -331,6 +332,7 @@ pub fn palenight() -> UserThemeFamily { scrollbar_thumb_hover_background: Some(rgba(0x694ca4cc).into()), scrollbar_thumb_border: Some(rgba(0x694ca466).into()), scrollbar_track_background: Some(rgba(0x292d3eff).into()), + editor_foreground: Some(rgba(0xbfc7d5ff).into()), editor_background: Some(rgba(0x292d3eff).into()), editor_gutter_background: Some(rgba(0x292d3eff).into()), editor_line_number: Some(rgba(0x4c5374ff).into()), @@ -616,6 +618,7 @@ pub fn palenight() -> UserThemeFamily { scrollbar_thumb_hover_background: Some(rgba(0x694ca4cc).into()), scrollbar_thumb_border: Some(rgba(0x694ca466).into()), scrollbar_track_background: Some(rgba(0x292d3eff).into()), + editor_foreground: Some(rgba(0xbfc7d5ff).into()), editor_background: Some(rgba(0x292d3eff).into()), editor_gutter_background: Some(rgba(0x292d3eff).into()), editor_line_number: Some(rgba(0x4c5374ff).into()), diff --git a/crates/theme2/src/themes/rose_pine.rs b/crates/theme2/src/themes/rose_pine.rs index d9091df347..a09364405f 100644 --- a/crates/theme2/src/themes/rose_pine.rs +++ b/crates/theme2/src/themes/rose_pine.rs @@ -47,6 +47,7 @@ pub fn rose_pine() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x6e6a8633).into()), scrollbar_track_background: Some(rgba(0x191724ff).into()), scrollbar_track_border: Some(rgba(0x6e6a8666).into()), + editor_foreground: Some(rgba(0xe0def4ff).into()), editor_background: Some(rgba(0x191724ff).into()), editor_gutter_background: Some(rgba(0x191724ff).into()), editor_line_number: Some(rgba(0x908caaff).into()), @@ -306,6 +307,7 @@ pub fn rose_pine() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x817c9c26).into()), scrollbar_track_background: Some(rgba(0x232136ff).into()), scrollbar_track_border: Some(rgba(0x817c9c4d).into()), + editor_foreground: Some(rgba(0xe0def4ff).into()), editor_background: Some(rgba(0x232136ff).into()), editor_gutter_background: Some(rgba(0x232136ff).into()), editor_line_number: Some(rgba(0x908caaff).into()), @@ -565,6 +567,7 @@ pub fn rose_pine() -> UserThemeFamily { scrollbar_thumb_border: Some(rgba(0x6e6a8614).into()), scrollbar_track_background: Some(rgba(0xfaf4edff).into()), scrollbar_track_border: Some(rgba(0x6e6a8626).into()), + editor_foreground: Some(rgba(0x575279ff).into()), editor_background: Some(rgba(0xfaf4edff).into()), editor_gutter_background: Some(rgba(0xfaf4edff).into()), editor_line_number: Some(rgba(0x797593ff).into()), diff --git a/crates/theme2/src/themes/solarized.rs b/crates/theme2/src/themes/solarized.rs index 25799bea28..9807a6cd3d 100644 --- a/crates/theme2/src/themes/solarized.rs +++ b/crates/theme2/src/themes/solarized.rs @@ -42,6 +42,7 @@ pub fn solarized() -> UserThemeFamily { tab_inactive_background: Some(rgba(0x004052ff).into()), tab_active_background: Some(rgba(0x002b37ff).into()), scrollbar_track_background: Some(rgba(0x002b36ff).into()), + editor_foreground: Some(rgba(0xbbbbbbff).into()), editor_background: Some(rgba(0x002b36ff).into()), editor_gutter_background: Some(rgba(0x002b36ff).into()), editor_line_number: Some(rgba(0x566c74ff).into()), @@ -307,6 +308,7 @@ pub fn solarized() -> UserThemeFamily { tab_inactive_background: Some(rgba(0xd3cbb7ff).into()), tab_active_background: Some(rgba(0xfdf6e3ff).into()), scrollbar_track_background: Some(rgba(0xfdf6e3ff).into()), + editor_foreground: Some(rgba(0x333333ff).into()), editor_background: Some(rgba(0xfdf6e3ff).into()), editor_gutter_background: Some(rgba(0xfdf6e3ff).into()), editor_line_number: Some(rgba(0x9ca8a6ff).into()), diff --git a/crates/theme_importer/src/theme_printer.rs b/crates/theme_importer/src/theme_printer.rs index 78c8719105..4726c90c6d 100644 --- a/crates/theme_importer/src/theme_printer.rs +++ b/crates/theme_importer/src/theme_printer.rs @@ -201,6 +201,7 @@ impl<'a> Debug for ThemeColorsRefinementPrinter<'a> { self.0.scrollbar_track_background, ), ("scrollbar_track_border", self.0.scrollbar_track_border), + ("editor_foreground", self.0.editor_foreground), ("editor_background", self.0.editor_background), ("editor_gutter_background", self.0.editor_gutter_background), ( diff --git a/crates/theme_importer/src/vscode/converter.rs b/crates/theme_importer/src/vscode/converter.rs index c9a07a1f7f..46d9c3d086 100644 --- a/crates/theme_importer/src/vscode/converter.rs +++ b/crates/theme_importer/src/vscode/converter.rs @@ -132,6 +132,11 @@ impl VsCodeThemeConverter { .as_ref() .traverse(|color| try_parse_color(&color))?; + let vscode_editor_foreground = vscode_colors + .editor_foreground + .as_ref() + .traverse(|color| try_parse_color(&color))?; + let vscode_editor_background = vscode_colors .editor_background .as_ref() @@ -142,6 +147,16 @@ impl VsCodeThemeConverter { .as_ref() .traverse(|color| try_parse_color(&color))?; + let vscode_token_colors_foreground = self + .theme + .token_colors + .iter() + .find(|token_color| token_color.scope.is_none()) + .and_then(|token_color| token_color.settings.foreground.as_ref()) + .traverse(|color| try_parse_color(&color)) + .ok() + .flatten(); + Ok(ThemeColorsRefinement { border: vscode_panel_border, border_variant: vscode_panel_border, @@ -197,16 +212,7 @@ impl VsCodeThemeConverter { .foreground .as_ref() .traverse(|color| try_parse_color(&color))? - .or_else(|| { - self.theme - .token_colors - .iter() - .find(|token_color| token_color.scope.is_none()) - .and_then(|token_color| token_color.settings.foreground.as_ref()) - .traverse(|color| try_parse_color(&color)) - .ok() - .flatten() - }), + .or(vscode_token_colors_foreground), text_muted: vscode_colors .tab_inactive_foreground .as_ref() @@ -226,6 +232,7 @@ impl VsCodeThemeConverter { .as_ref() .traverse(|color| try_parse_color(&color))? .or(vscode_editor_background), + editor_foreground: vscode_editor_foreground.or(vscode_token_colors_foreground), editor_background: vscode_editor_background, editor_gutter_background: vscode_editor_background, editor_line_number: vscode_colors diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index f9e294763b..54480f0b68 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -41,7 +41,7 @@ pub trait Panel: FocusableView + EventEmitter { } pub trait PanelHandle: Send + Sync { - fn entity_id(&self) -> EntityId; + fn panel_id(&self) -> EntityId; fn persistent_name(&self) -> &'static str; fn position(&self, cx: &WindowContext) -> DockPosition; fn position_is_valid(&self, position: DockPosition, cx: &WindowContext) -> bool; @@ -62,7 +62,7 @@ impl PanelHandle for View where T: Panel, { - fn entity_id(&self) -> EntityId { + fn panel_id(&self) -> EntityId { Entity::entity_id(self) } @@ -135,7 +135,7 @@ pub struct Dock { is_open: bool, active_panel_index: usize, focus_handle: FocusHandle, - focus_subscription: Subscription, + _focus_subscription: Subscription, } impl FocusableView for Dock { @@ -187,7 +187,6 @@ struct PanelEntry { pub struct PanelButtons { dock: View, - workspace: WeakView, } impl Dock { @@ -204,7 +203,7 @@ impl Dock { active_panel_index: 0, is_open: false, focus_handle, - focus_subscription, + _focus_subscription: focus_subscription, } } @@ -261,7 +260,7 @@ impl Dock { pub fn set_panel_zoomed(&mut self, panel: &AnyView, zoomed: bool, cx: &mut ViewContext) { for entry in &mut self.panel_entries { - if entry.panel.entity_id() == panel.entity_id() { + if entry.panel.panel_id() == panel.entity_id() { if zoomed != entry.panel.is_zoomed(cx) { entry.panel.set_zoomed(zoomed, cx); } @@ -309,7 +308,7 @@ impl Dock { let was_visible = this.is_open() && this.visible_panel().map_or(false, |active_panel| { - active_panel.entity_id() == Entity::entity_id(&panel) + active_panel.panel_id() == Entity::entity_id(&panel) }); this.remove_panel(&panel, cx); @@ -351,7 +350,7 @@ impl Dock { if let Some(ix) = this .panel_entries .iter() - .position(|entry| entry.panel.entity_id() == Entity::entity_id(&panel)) + .position(|entry| entry.panel.panel_id() == Entity::entity_id(&panel)) { this.set_open(true, cx); this.activate_panel(ix, cx); @@ -361,7 +360,7 @@ impl Dock { PanelEvent::Close => { if this .visible_panel() - .map_or(false, |p| p.entity_id() == Entity::entity_id(&panel)) + .map_or(false, |p| p.panel_id() == Entity::entity_id(&panel)) { this.set_open(false, cx); } @@ -389,7 +388,7 @@ impl Dock { if let Some(panel_ix) = self .panel_entries .iter() - .position(|entry| entry.panel.entity_id() == Entity::entity_id(panel)) + .position(|entry| entry.panel.panel_id() == Entity::entity_id(panel)) { if panel_ix == self.active_panel_index { self.active_panel_index = 0; @@ -450,7 +449,7 @@ impl Dock { pub fn panel_size(&self, panel: &dyn PanelHandle, cx: &WindowContext) -> Option { self.panel_entries .iter() - .find(|entry| entry.panel.entity_id() == panel.entity_id()) + .find(|entry| entry.panel.panel_id() == panel.panel_id()) .map(|entry| entry.panel.size(cx)) } @@ -493,7 +492,9 @@ impl Render for Dock { let handler = div() .id("resize-handle") .bg(cx.theme().colors().border) - .on_drag(move |cx| cx.build_view(|_| DraggedDock(position))) + .on_drag(DraggedDock(position), |dock, cx| { + cx.build_view(|_| dock.clone()) + }) .on_click(cx.listener(|v, e: &ClickEvent, cx| { if e.down.button == MouseButton::Left && e.down.click_count == 2 { v.resize_active_panel(None, cx) @@ -547,166 +548,12 @@ impl Render for Dock { } impl PanelButtons { - pub fn new( - dock: View, - workspace: WeakView, - cx: &mut ViewContext, - ) -> Self { + pub fn new(dock: View, cx: &mut ViewContext) -> Self { cx.observe(&dock, |_, _, cx| cx.notify()).detach(); - Self { dock, workspace } + Self { dock } } } -// impl Render for PanelButtons { -// type Element = (); - -// fn render(&mut self, cx: &mut ViewContext) -> Self::Element { -// todo!("") -// } - -// fn ui_name() -> &'static str { -// "PanelButtons" -// } - -// fn render(&mut self, cx: &mut ViewContext) -> AnyElement { -// let theme = &settings::get::(cx).theme; -// let tooltip_style = theme.tooltip.clone(); -// let theme = &theme.workspace.status_bar.panel_buttons; -// let button_style = theme.button.clone(); -// let dock = self.dock.read(cx); -// let active_ix = dock.active_panel_index; -// let is_open = dock.is_open; -// let dock_position = dock.position; -// let group_style = match dock_position { -// DockPosition::Left => theme.group_left, -// DockPosition::Bottom => theme.group_bottom, -// DockPosition::Right => theme.group_right, -// }; -// let menu_corner = match dock_position { -// DockPosition::Left => AnchorCorner::BottomLeft, -// DockPosition::Bottom | DockPosition::Right => AnchorCorner::BottomRight, -// }; - -// let panels = dock -// .panel_entries -// .iter() -// .map(|item| (item.panel.clone(), item.context_menu.clone())) -// .collect::>(); -// Flex::row() -// .with_children(panels.into_iter().enumerate().filter_map( -// |(panel_ix, (view, context_menu))| { -// let icon_path = view.icon_path(cx)?; -// let is_active = is_open && panel_ix == active_ix; -// let (tooltip, tooltip_action) = if is_active { -// ( -// format!("Close {} dock", dock_position.to_label()), -// Some(match dock_position { -// DockPosition::Left => crate::ToggleLeftDock.boxed_clone(), -// DockPosition::Bottom => crate::ToggleBottomDock.boxed_clone(), -// DockPosition::Right => crate::ToggleRightDock.boxed_clone(), -// }), -// ) -// } else { -// view.icon_tooltip(cx) -// }; -// Some( -// Stack::new() -// .with_child( -// MouseEventHandler::new::(panel_ix, cx, |state, cx| { -// let style = button_style.in_state(is_active); - -// let style = style.style_for(state); -// Flex::row() -// .with_child( -// Svg::new(icon_path) -// .with_color(style.icon_color) -// .constrained() -// .with_width(style.icon_size) -// .aligned(), -// ) -// .with_children(if let Some(label) = view.icon_label(cx) { -// Some( -// Label::new(label, style.label.text.clone()) -// .contained() -// .with_style(style.label.container) -// .aligned(), -// ) -// } else { -// None -// }) -// .constrained() -// .with_height(style.icon_size) -// .contained() -// .with_style(style.container) -// }) -// .with_cursor_style(CursorStyle::PointingHand) -// .on_click(MouseButton::Left, { -// let tooltip_action = -// tooltip_action.as_ref().map(|action| action.boxed_clone()); -// move |_, this, cx| { -// if let Some(tooltip_action) = &tooltip_action { -// let window = cx.window(); -// let view_id = this.workspace.id(); -// let tooltip_action = tooltip_action.boxed_clone(); -// cx.spawn(|_, mut cx| async move { -// window.dispatch_action( -// view_id, -// &*tooltip_action, -// &mut cx, -// ); -// }) -// .detach(); -// } -// } -// }) -// .on_click(MouseButton::Right, { -// let view = view.clone(); -// let menu = context_menu.clone(); -// move |_, _, cx| { -// const POSITIONS: [DockPosition; 3] = [ -// DockPosition::Left, -// DockPosition::Right, -// DockPosition::Bottom, -// ]; - -// menu.update(cx, |menu, cx| { -// let items = POSITIONS -// .into_iter() -// .filter(|position| { -// *position != dock_position -// && view.position_is_valid(*position, cx) -// }) -// .map(|position| { -// let view = view.clone(); -// ContextMenuItem::handler( -// format!("Dock {}", position.to_label()), -// move |cx| view.set_position(position, cx), -// ) -// }) -// .collect(); -// menu.show(Default::default(), menu_corner, items, cx); -// }) -// } -// }) -// .with_tooltip::( -// panel_ix, -// tooltip, -// tooltip_action, -// tooltip_style.clone(), -// cx, -// ), -// ) -// .with_child(ChildView::new(&context_menu, cx)), -// ) -// }, -// )) -// .contained() -// .with_style(group_style) -// .into_any() -// } -// } - -// here be kittens impl Render for PanelButtons { type Element = Div; diff --git a/crates/workspace2/src/item.rs b/crates/workspace2/src/item.rs index c0242ffa17..43597f21a7 100644 --- a/crates/workspace2/src/item.rs +++ b/crates/workspace2/src/item.rs @@ -919,7 +919,7 @@ pub mod test { impl EventEmitter for TestItem {} impl FocusableView for TestItem { - fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { + fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle { self.focus_handle.clone() } } @@ -941,8 +941,8 @@ pub mod test { fn tab_content( &self, detail: Option, - selected: bool, - cx: &ui::prelude::WindowContext, + _selected: bool, + _cx: &ui::prelude::WindowContext, ) -> AnyElement { self.tab_detail.set(detail); gpui::div().into_any_element() diff --git a/crates/workspace2/src/modal_layer.rs b/crates/workspace2/src/modal_layer.rs index e0a6395f31..ff1de6548d 100644 --- a/crates/workspace2/src/modal_layer.rs +++ b/crates/workspace2/src/modal_layer.rs @@ -5,7 +5,7 @@ use gpui::{ use ui::{h_stack, v_stack}; pub trait ModalView: ManagedView { - fn on_before_dismiss(&mut self, cx: &mut ViewContext) -> bool { + fn on_before_dismiss(&mut self, _: &mut ViewContext) -> bool { true } } @@ -27,7 +27,7 @@ impl ModalViewHandle for View { pub struct ActiveModal { modal: Box, - subscription: Subscription, + _subscription: Subscription, previous_focus_handle: Option, focus_handle: FocusHandle, } @@ -63,7 +63,7 @@ impl ModalLayer { { self.active_modal = Some(ActiveModal { modal: Box::new(new_modal.clone()), - subscription: cx.subscribe(&new_modal, |this, modal, _: &DismissEvent, cx| { + _subscription: cx.subscribe(&new_modal, |this, _, _: &DismissEvent, cx| { this.hide_modal(cx); }), previous_focus_handle: cx.focused(), diff --git a/crates/workspace2/src/notifications.rs b/crates/workspace2/src/notifications.rs index 63475c2aba..a692388a06 100644 --- a/crates/workspace2/src/notifications.rs +++ b/crates/workspace2/src/notifications.rs @@ -104,12 +104,9 @@ impl Workspace { }) { let notification = build_notification(cx); - cx.subscribe( - ¬ification, - move |this, handle, event: &DismissEvent, cx| { - this.dismiss_notification_internal(type_id, id, cx); - }, - ) + cx.subscribe(¬ification, move |this, _, _: &DismissEvent, cx| { + this.dismiss_notification_internal(type_id, id, cx); + }) .detach(); self.notifications .push((type_id, id, Box::new(notification))); @@ -173,21 +170,15 @@ impl Workspace { pub mod simple_message_notification { use gpui::{ - div, AnyElement, AppContext, DismissEvent, Div, EventEmitter, InteractiveElement, - ParentElement, Render, SharedString, StatefulInteractiveElement, Styled, TextStyle, - ViewContext, + div, DismissEvent, Div, EventEmitter, InteractiveElement, ParentElement, Render, + SharedString, StatefulInteractiveElement, Styled, ViewContext, }; use std::sync::Arc; use ui::prelude::*; use ui::{h_stack, v_stack, Button, Icon, IconElement, Label, StyledExt}; - enum NotificationMessage { - Text(SharedString), - Element(fn(TextStyle, &AppContext) -> AnyElement), - } - pub struct MessageNotification { - message: NotificationMessage, + message: SharedString, on_click: Option)>>, click_message: Option, } @@ -200,23 +191,12 @@ pub mod simple_message_notification { S: Into, { Self { - message: NotificationMessage::Text(message.into()), + message: message.into(), on_click: None, click_message: None, } } - // not needed I think (only for the "new panel" toast, which is outdated now) - // pub fn new_element( - // message: fn(TextStyle, &AppContext) -> AnyElement, - // ) -> MessageNotification { - // Self { - // message: NotificationMessage::Element(message), - // on_click: None, - // click_message: None, - // } - // } - pub fn with_click_message(mut self, message: S) -> Self where S: Into, @@ -248,18 +228,13 @@ pub mod simple_message_notification { .child( h_stack() .justify_between() - .child(div().max_w_80().child(match &self.message { - NotificationMessage::Text(text) => Label::new(text.clone()), - NotificationMessage::Element(element) => { - todo!() - } - })) + .child(div().max_w_80().child(Label::new(self.message.clone()))) .child( div() .id("cancel") .child(IconElement::new(Icon::Close)) .cursor_pointer() - .on_click(cx.listener(|this, event, cx| this.dismiss(cx))), + .on_click(cx.listener(|this, _, cx| this.dismiss(cx))), ), ) .children(self.click_message.iter().map(|message| { diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index a55469fbad..4c436daada 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -7,7 +7,7 @@ use crate::{ use anyhow::Result; use collections::{HashMap, HashSet, VecDeque}; use gpui::{ - actions, impl_actions, overlay, prelude::*, Action, AnchorCorner, AnyWeakView, AppContext, + actions, impl_actions, overlay, prelude::*, Action, AnchorCorner, AppContext, AsyncWindowContext, DismissEvent, Div, EntityId, EventEmitter, FocusHandle, Focusable, FocusableView, Model, MouseButton, NavigationDirection, Pixels, Point, PromptLevel, Render, ScrollHandle, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext, @@ -164,11 +164,6 @@ impl fmt::Debug for Event { } } -struct FocusedView { - view: AnyWeakView, - focus_handle: FocusHandle, -} - pub struct Pane { focus_handle: FocusHandle, items: Vec>, @@ -187,7 +182,7 @@ pub struct Pane { // can_drop: Rc, &WindowContext) -> bool>, can_split: bool, // render_tab_bar_buttons: Rc) -> AnyElement>, - subscriptions: Vec, + _subscriptions: Vec, tab_bar_scroll_handle: ScrollHandle, } @@ -231,6 +226,7 @@ pub struct NavigationEntry { pub timestamp: usize, } +#[derive(Clone)] struct DraggedTab { pub pane: View, pub ix: usize, @@ -431,14 +427,10 @@ impl Pane { // }) // .into_any() // }), - subscriptions, + _subscriptions: subscriptions, } } - pub(crate) fn workspace(&self) -> &WeakView { - &self.workspace - } - pub fn has_focus(&self, cx: &WindowContext) -> bool { // todo!(); // inline this manually self.focus_handle.contains_focused(cx) @@ -1467,21 +1459,6 @@ impl Pane { let label = item.tab_content(Some(detail), is_active, cx); let close_side = &ItemSettings::get_global(cx).close_position; - 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_background, - cx.theme().colors().ghost_element_hover, - cx.theme().colors().ghost_element_active, - ), - true => ( - cx.theme().colors().text, - cx.theme().colors().tab_active_background, - cx.theme().colors().element_hover, - cx.theme().colors().element_active, - ), - }; - let indicator = maybe!({ let indicator_color = match (item.has_conflict(cx), item.is_dirty(cx)) { (true, _) => Color::Warning, @@ -1497,56 +1474,55 @@ impl Pane { let is_last_item = ix == self.items.len() - 1; let position_relative_to_active_item = ix.cmp(&self.active_item_index); - let tab = - Tab::new(ix) - .position(if is_first_item { - TabPosition::First - } else if is_last_item { - TabPosition::Last - } else { - TabPosition::Middle(position_relative_to_active_item) - }) - .close_side(match close_side { - ClosePosition::Left => ui::TabCloseSide::Start, - ClosePosition::Right => ui::TabCloseSide::End, - }) - .selected(is_active) - .on_click(cx.listener(move |pane: &mut Self, event, cx| { - pane.activate_item(ix, true, true, cx) - })) - .on_drag({ - let pane = cx.view().clone(); - move |cx| { - cx.build_view(|cx| DraggedTab { - pane: pane.clone(), - detail, - item_id, - is_active, - ix, - }) - } - }) - .drag_over::(|tab| tab.bg(cx.theme().colors().tab_active_background)) - .on_drop( - cx.listener(move |this, dragged_tab: &View, cx| { - this.handle_tab_drop(dragged_tab, ix, cx) - }), - ) - .when_some(item.tab_tooltip_text(cx), |tab, text| { - tab.tooltip(move |cx| Tooltip::text(text.clone(), cx)) - }) - .start_slot::(indicator) - .end_slot( - IconButton::new("close tab", Icon::Close) - .icon_color(Color::Muted) - .size(ButtonSize::None) - .icon_size(IconSize::XSmall) - .on_click(cx.listener(move |pane, _, cx| { - pane.close_item_by_id(item_id, SaveIntent::Close, cx) - .detach_and_log_err(cx); - })), - ) - .child(label); + let tab = Tab::new(ix) + .position(if is_first_item { + TabPosition::First + } else if is_last_item { + TabPosition::Last + } else { + TabPosition::Middle(position_relative_to_active_item) + }) + .close_side(match close_side { + ClosePosition::Left => ui::TabCloseSide::Start, + ClosePosition::Right => ui::TabCloseSide::End, + }) + .selected(is_active) + .on_click( + cx.listener(move |pane: &mut Self, _, cx| pane.activate_item(ix, true, true, cx)), + ) + .on_drag( + DraggedTab { + pane: cx.view().clone(), + detail, + item_id, + is_active, + ix, + }, + |tab, cx| cx.build_view(|_| tab.clone()), + ) + .drag_over::(|tab| tab.bg(cx.theme().colors().tab_active_background)) + .drag_over::(|tab| tab.bg(gpui::red())) + .on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| { + this.handle_tab_drop(dragged_tab, ix, cx) + })) + .on_drop(cx.listener(move |this, entry_id: &ProjectEntryId, cx| { + this.handle_project_entry_drop(entry_id, cx) + })) + .when_some(item.tab_tooltip_text(cx), |tab, text| { + tab.tooltip(move |cx| Tooltip::text(text.clone(), cx)) + }) + .start_slot::(indicator) + .end_slot( + IconButton::new("close tab", Icon::Close) + .icon_color(Color::Muted) + .size(ButtonSize::None) + .icon_size(IconSize::XSmall) + .on_click(cx.listener(move |pane, _, cx| { + pane.close_item_by_id(item_id, SaveIntent::Close, cx) + .detach_and_log_err(cx); + })), + ) + .child(label); let single_entry_to_resolve = { let item_entries = self.items[ix].project_entry_ids(cx); @@ -1616,12 +1592,12 @@ impl Pane { IconButton::new("plus", Icon::Plus) .icon_size(IconSize::Small) .on_click(cx.listener(|this, _, cx| { - let menu = ContextMenu::build(cx, |menu, cx| { + let menu = ContextMenu::build(cx, |menu, _| { menu.action("New File", NewFile.boxed_clone()) .action("New Terminal", NewCenterTerminal.boxed_clone()) .action("New Search", NewSearch.boxed_clone()) }); - cx.subscribe(&menu, |this, _, event: &DismissEvent, cx| { + cx.subscribe(&menu, |this, _, _: &DismissEvent, cx| { this.focus(cx); this.new_item_menu = None; }) @@ -1640,13 +1616,13 @@ impl Pane { IconButton::new("split", Icon::Split) .icon_size(IconSize::Small) .on_click(cx.listener(|this, _, cx| { - let menu = ContextMenu::build(cx, |menu, cx| { + let menu = ContextMenu::build(cx, |menu, _| { menu.action("Split Right", SplitRight.boxed_clone()) .action("Split Left", SplitLeft.boxed_clone()) .action("Split Up", SplitUp.boxed_clone()) .action("Split Down", SplitDown.boxed_clone()) }); - cx.subscribe(&menu, |this, _, event: &DismissEvent, cx| { + cx.subscribe(&menu, |this, _, _: &DismissEvent, cx| { this.focus(cx); this.split_item_menu = None; }) @@ -1677,11 +1653,13 @@ impl Pane { .drag_over::(|bar| { bar.bg(cx.theme().colors().tab_active_background) }) - .on_drop( - cx.listener(move |this, dragged_tab: &View, cx| { - this.handle_tab_drop(dragged_tab, this.items.len(), cx) - }), - ), + .drag_over::(|bar| bar.bg(gpui::red())) + .on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| { + this.handle_tab_drop(dragged_tab, this.items.len(), cx) + })) + .on_drop(cx.listener(move |this, entry_id: &ProjectEntryId, cx| { + this.handle_project_entry_drop(entry_id, cx) + })), ) } @@ -1743,16 +1721,15 @@ impl Pane { fn handle_tab_drop( &mut self, - dragged_tab: &View, + dragged_tab: &DraggedTab, ix: usize, cx: &mut ViewContext<'_, Pane>, ) { - let dragged_tab = dragged_tab.read(cx); let item_id = dragged_tab.item_id; let from_pane = dragged_tab.pane.clone(); let to_pane = cx.view().clone(); self.workspace - .update(cx, |workspace, cx| { + .update(cx, |_, cx| { cx.defer(move |workspace, cx| { workspace.move_item(from_pane, to_pane, item_id, ix, cx); }); @@ -1760,28 +1737,69 @@ impl Pane { .log_err(); } + fn handle_project_entry_drop( + &mut self, + project_entry_id: &ProjectEntryId, + cx: &mut ViewContext<'_, Pane>, + ) { + let to_pane = cx.view().downgrade(); + let project_entry_id = *project_entry_id; + self.workspace + .update(cx, |_, cx| { + cx.defer(move |workspace, cx| { + if let Some(path) = workspace + .project() + .read(cx) + .path_for_entry(project_entry_id, cx) + { + workspace + .open_path(path, Some(to_pane), true, cx) + .detach_and_log_err(cx); + } + }); + }) + .log_err(); + } + fn handle_split_tab_drop( &mut self, - dragged_tab: &View, + dragged_tab: &DraggedTab, split_direction: SplitDirection, cx: &mut ViewContext<'_, Pane>, ) { - let dragged_tab = dragged_tab.read(cx); let item_id = dragged_tab.item_id; let from_pane = dragged_tab.pane.clone(); let to_pane = cx.view().clone(); self.workspace - .update(cx, |workspace, cx| { + .update(cx, |_, cx| { cx.defer(move |workspace, cx| { - let item = from_pane + let pane = workspace.split_pane(to_pane, split_direction, cx); + workspace.move_item(from_pane, pane, item_id, 0, cx); + }); + }) + .log_err(); + } + + fn handle_split_project_entry_drop( + &mut self, + project_entry_id: &ProjectEntryId, + split_direction: SplitDirection, + cx: &mut ViewContext<'_, Pane>, + ) { + let project_entry_id = *project_entry_id; + let current_pane = cx.view().clone(); + self.workspace + .update(cx, |_, cx| { + cx.defer(move |workspace, cx| { + if let Some(path) = workspace + .project() .read(cx) - .items() - .find(|item| item.item_id() == item_id) - .map(|item| item.boxed_clone()); - if let Some(item) = item { - if let Some(item) = item.clone_on_split(workspace.database_id(), cx) { - workspace.split_item(split_direction, item, cx); - } + .path_for_entry(project_entry_id, cx) + { + let pane = workspace.split_pane(current_pane, split_direction, cx); + workspace + .open_path(path, Some(pane.downgrade()), true, cx) + .detach_and_log_err(cx); } }); }) @@ -1799,8 +1817,6 @@ impl Render for Pane { type Element = Focusable
; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { - let this = cx.view().downgrade(); - v_stack() .key_context("Pane") .track_focus(&self.focus_handle) @@ -1894,11 +1910,13 @@ impl Render for Pane { .full() .z_index(1) .drag_over::(|style| style.bg(drag_target_color)) - .on_drop(cx.listener( - move |this, dragged_tab: &View, cx| { - this.handle_tab_drop(dragged_tab, this.active_item_index(), cx) - }, - )), + .drag_over::(|style| style.bg(gpui::red())) + .on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| { + this.handle_tab_drop(dragged_tab, this.active_item_index(), cx) + })) + .on_drop(cx.listener(move |this, entry_id: &ProjectEntryId, cx| { + this.handle_project_entry_drop(entry_id, cx) + })), ) .children( [ @@ -1915,9 +1933,15 @@ impl Render for Pane { .invisible() .bg(drag_target_color) .drag_over::(|style| style.visible()) + .drag_over::(|style| style.visible()) + .on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| { + this.handle_split_tab_drop(dragged_tab, direction, cx) + })) .on_drop(cx.listener( - move |this, dragged_tab: &View, cx| { - this.handle_split_tab_drop(dragged_tab, direction, cx) + move |this, entry_id: &ProjectEntryId, cx| { + this.handle_split_project_entry_drop( + entry_id, direction, cx, + ) }, )); match direction { diff --git a/crates/workspace2/src/pane_group.rs b/crates/workspace2/src/pane_group.rs index 5d79109dee..966e2c6341 100644 --- a/crates/workspace2/src/pane_group.rs +++ b/crates/workspace2/src/pane_group.rs @@ -16,7 +16,7 @@ const HANDLE_HITBOX_SIZE: f32 = 10.0; //todo!(change this back to 4) const HORIZONTAL_MIN_SIZE: f32 = 80.; const VERTICAL_MIN_SIZE: f32 = 100.; -#[derive(Clone, PartialEq)] +#[derive(Clone)] pub struct PaneGroup { pub(crate) root: Member, } @@ -121,7 +121,7 @@ impl PaneGroup { } } -#[derive(Clone, PartialEq)] +#[derive(Clone)] pub(crate) enum Member { Axis(PaneAxis), Pane(View), @@ -426,12 +426,6 @@ pub(crate) struct PaneAxis { pub bounding_boxes: Arc>>>>, } -impl PartialEq for PaneAxis { - fn eq(&self, other: &Self) -> bool { - todo!() - } -} - impl PaneAxis { pub fn new(axis: Axis, members: Vec) -> Self { let flexes = Arc::new(Mutex::new(vec![1.; members.len()])); @@ -816,7 +810,7 @@ mod element { proposed_current_pixel_change -= current_pixel_change; } - // todo!(reserialize workspace) + // todo!(schedule serialize) // workspace.schedule_serialize(cx); cx.notify(); } @@ -851,7 +845,7 @@ mod element { cx.on_mouse_event({ let dragged_handle = dragged_handle.clone(); - move |e: &MouseDownEvent, phase, cx| { + move |e: &MouseDownEvent, phase, _cx| { if phase.bubble() && handle_bounds.contains(&e.position) { dragged_handle.replace(Some(ix)); } @@ -859,7 +853,7 @@ mod element { }); cx.on_mouse_event(move |e: &MouseMoveEvent, phase, cx| { let dragged_handle = dragged_handle.borrow(); - if *dragged_handle == Some(ix) { + if phase.bubble() && *dragged_handle == Some(ix) { Self::compute_resize(&flexes, e, ix, axis, axis_bounds, cx) } }); @@ -912,7 +906,7 @@ mod element { let mut bounding_boxes = self.bounding_boxes.lock(); bounding_boxes.clear(); - for (ix, mut child) in self.children.iter_mut().enumerate() { + for (ix, child) in self.children.iter_mut().enumerate() { //todo!(active_pane_magnification) // If usign active pane magnification, need to switch to using // 1 for all non-active panes, and then the magnification for the @@ -949,7 +943,7 @@ mod element { cx.with_z_index(1, |cx| { cx.on_mouse_event({ let state = state.clone(); - move |e: &MouseUpEvent, phase, cx| { + move |_: &MouseUpEvent, phase, _cx| { if phase.bubble() { state.replace(None); } @@ -968,402 +962,4 @@ mod element { fn flex_values_in_bounds(flexes: &[f32]) -> bool { (flexes.iter().copied().sum::() - flexes.len() as f32).abs() < 0.001 } - // // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc}; - - // // use gpui::{ - // // geometry::{ - // // rect::Bounds, - // // vector::{vec2f, Vector2F}, - // // }, - // // json::{self, ToJson}, - // // platform::{CursorStyle, MouseButton}, - // // scene::MouseDrag, - // // AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, BoundsExt, - // // SizeConstraint, Vector2FExt, ViewContext, - // // }; - - // use crate::{ - // pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE}, - // Workspace, WorkspaceSettings, - // }; - - // pub struct PaneAxisElement { - // axis: Axis, - // basis: usize, - // active_pane_ix: Option, - // flexes: Rc>>, - // children: Vec>, - // bounding_boxes: Rc>>>>, - // } - - // impl PaneAxisElement { - // pub fn new( - // axis: Axis, - // basis: usize, - // flexes: Rc>>, - // bounding_boxes: Rc>>>>, - // ) -> Self { - // Self { - // axis, - // basis, - // flexes, - // bounding_boxes, - // active_pane_ix: None, - // children: Default::default(), - // } - // } - - // pub fn set_active_pane(&mut self, active_pane_ix: Option) { - // self.active_pane_ix = active_pane_ix; - // } - - // fn layout_children( - // &mut self, - // active_pane_magnification: f32, - // constraint: SizeConstraint, - // remaining_space: &mut f32, - // remaining_flex: &mut f32, - // cross_axis_max: &mut f32, - // view: &mut Workspace, - // cx: &mut ViewContext, - // ) { - // let flexes = self.flexes.borrow(); - // let cross_axis = self.axis.invert(); - // for (ix, child) in self.children.iter_mut().enumerate() { - // let flex = if active_pane_magnification != 1. { - // if let Some(active_pane_ix) = self.active_pane_ix { - // if ix == active_pane_ix { - // active_pane_magnification - // } else { - // 1. - // } - // } else { - // 1. - // } - // } else { - // flexes[ix] - // }; - - // let child_size = if *remaining_flex == 0.0 { - // *remaining_space - // } else { - // let space_per_flex = *remaining_space / *remaining_flex; - // space_per_flex * flex - // }; - - // let child_constraint = match self.axis { - // Axis::Horizontal => SizeConstraint::new( - // vec2f(child_size, constraint.min.y()), - // vec2f(child_size, constraint.max.y()), - // ), - // Axis::Vertical => SizeConstraint::new( - // vec2f(constraint.min.x(), child_size), - // vec2f(constraint.max.x(), child_size), - // ), - // }; - // let child_size = child.layout(child_constraint, view, cx); - // *remaining_space -= child_size.along(self.axis); - // *remaining_flex -= flex; - // *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis)); - // } - // } - - // fn handle_resize( - // flexes: Rc>>, - // axis: Axis, - // preceding_ix: usize, - // child_start: Vector2F, - // drag_bounds: Bounds, - // ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext) { - // let size = move |ix, flexes: &[f32]| { - // drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32) - // }; - - // move |drag, workspace: &mut Workspace, cx| { - // if drag.end { - // // TODO: Clear cascading resize state - // return; - // } - // let min_size = match axis { - // Axis::Horizontal => HORIZONTAL_MIN_SIZE, - // Axis::Vertical => VERTICAL_MIN_SIZE, - // }; - // let mut flexes = flexes.borrow_mut(); - - // // Don't allow resizing to less than the minimum size, if elements are already too small - // if min_size - 1. > size(preceding_ix, flexes.as_slice()) { - // return; - // } - - // let mut proposed_current_pixel_change = (drag.position - child_start).along(axis) - // - size(preceding_ix, flexes.as_slice()); - - // let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| { - // let flex_change = pixel_dx / drag_bounds.length_along(axis); - // let current_target_flex = flexes[target_ix] + flex_change; - // let next_target_flex = - // flexes[(target_ix as isize + next) as usize] - flex_change; - // (current_target_flex, next_target_flex) - // }; - - // let mut successors = from_fn({ - // let forward = proposed_current_pixel_change > 0.; - // let mut ix_offset = 0; - // let len = flexes.len(); - // move || { - // let result = if forward { - // (preceding_ix + 1 + ix_offset < len).then(|| preceding_ix + ix_offset) - // } else { - // (preceding_ix as isize - ix_offset as isize >= 0) - // .then(|| preceding_ix - ix_offset) - // }; - - // ix_offset += 1; - - // result - // } - // }); - - // while proposed_current_pixel_change.abs() > 0. { - // let Some(current_ix) = successors.next() else { - // break; - // }; - - // let next_target_size = f32::max( - // size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change, - // min_size, - // ); - - // let current_target_size = f32::max( - // size(current_ix, flexes.as_slice()) - // + size(current_ix + 1, flexes.as_slice()) - // - next_target_size, - // min_size, - // ); - - // let current_pixel_change = - // current_target_size - size(current_ix, flexes.as_slice()); - - // let (current_target_flex, next_target_flex) = - // flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice()); - - // flexes[current_ix] = current_target_flex; - // flexes[current_ix + 1] = next_target_flex; - - // proposed_current_pixel_change -= current_pixel_change; - // } - - // workspace.schedule_serialize(cx); - // cx.notify(); - // } - // } - // } - - // impl Extend> for PaneAxisElement { - // fn extend>>(&mut self, children: T) { - // self.children.extend(children); - // } - // } - - // impl Element for PaneAxisElement { - // type LayoutState = f32; - // type PaintState = (); - - // fn layout( - // &mut self, - // constraint: SizeConstraint, - // view: &mut Workspace, - // cx: &mut ViewContext, - // ) -> (Vector2F, Self::LayoutState) { - // debug_assert!(self.children.len() == self.flexes.borrow().len()); - - // let active_pane_magnification = - // settings::get::(cx).active_pane_magnification; - - // let mut remaining_flex = 0.; - - // if active_pane_magnification != 1. { - // let active_pane_flex = self - // .active_pane_ix - // .map(|_| active_pane_magnification) - // .unwrap_or(1.); - // remaining_flex += self.children.len() as f32 - 1. + active_pane_flex; - // } else { - // for flex in self.flexes.borrow().iter() { - // remaining_flex += flex; - // } - // } - - // let mut cross_axis_max: f32 = 0.0; - // let mut remaining_space = constraint.max_along(self.axis); - - // if remaining_space.is_infinite() { - // panic!("flex contains flexible children but has an infinite constraint along the flex axis"); - // } - - // self.layout_children( - // active_pane_magnification, - // constraint, - // &mut remaining_space, - // &mut remaining_flex, - // &mut cross_axis_max, - // view, - // cx, - // ); - - // let mut size = match self.axis { - // Axis::Horizontal => vec2f(constraint.max.x() - remaining_space, cross_axis_max), - // Axis::Vertical => vec2f(cross_axis_max, constraint.max.y() - remaining_space), - // }; - - // if constraint.min.x().is_finite() { - // size.set_x(size.x().max(constraint.min.x())); - // } - // if constraint.min.y().is_finite() { - // size.set_y(size.y().max(constraint.min.y())); - // } - - // if size.x() > constraint.max.x() { - // size.set_x(constraint.max.x()); - // } - // if size.y() > constraint.max.y() { - // size.set_y(constraint.max.y()); - // } - - // (size, remaining_space) - // } - - // fn paint( - // &mut self, - // bounds: Bounds, - // visible_bounds: Bounds, - // remaining_space: &mut Self::LayoutState, - // view: &mut Workspace, - // cx: &mut ViewContext, - // ) -> Self::PaintState { - // let can_resize = settings::get::(cx).active_pane_magnification == 1.; - // let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); - - // let overflowing = *remaining_space < 0.; - // if overflowing { - // cx.scene().push_layer(Some(visible_bounds)); - // } - - // let mut child_origin = bounds.origin(); - - // let mut bounding_boxes = self.bounding_boxes.borrow_mut(); - // bounding_boxes.clear(); - - // let mut children_iter = self.children.iter_mut().enumerate().peekable(); - // while let Some((ix, child)) = children_iter.next() { - // let child_start = child_origin.clone(); - // child.paint(child_origin, visible_bounds, view, cx); - - // bounding_boxes.push(Some(Bounds::new(child_origin, child.size()))); - - // match self.axis { - // Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0), - // Axis::Vertical => child_origin += vec2f(0.0, child.size().y()), - // } - - // if can_resize && children_iter.peek().is_some() { - // cx.scene().push_stacking_context(None, None); - - // let handle_origin = match self.axis { - // Axis::Horizontal => child_origin - vec2f(HANDLE_HITBOX_SIZE / 2., 0.0), - // Axis::Vertical => child_origin - vec2f(0.0, HANDLE_HITBOX_SIZE / 2.), - // }; - - // let handle_bounds = match self.axis { - // Axis::Horizontal => Bounds::new( - // handle_origin, - // vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()), - // ), - // Axis::Vertical => Bounds::new( - // handle_origin, - // vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE), - // ), - // }; - - // let style = match self.axis { - // Axis::Horizontal => CursorStyle::ResizeLeftRight, - // Axis::Vertical => CursorStyle::ResizeUpDown, - // }; - - // cx.scene().push_cursor_region(CursorRegion { - // bounds: handle_bounds, - // style, - // }); - - // enum ResizeHandle {} - // let mut mouse_region = MouseRegion::new::( - // cx.view_id(), - // self.basis + ix, - // handle_bounds, - // ); - // mouse_region = mouse_region - // .on_drag( - // MouseButton::Left, - // Self::handle_resize( - // self.flexes.clone(), - // self.axis, - // ix, - // child_start, - // visible_bounds.clone(), - // ), - // ) - // .on_click(MouseButton::Left, { - // let flexes = self.flexes.clone(); - // move |e, v: &mut Workspace, cx| { - // if e.click_count >= 2 { - // let mut borrow = flexes.borrow_mut(); - // *borrow = vec![1.; borrow.len()]; - // v.schedule_serialize(cx); - // cx.notify(); - // } - // } - // }); - // cx.scene().push_mouse_region(mouse_region); - - // cx.scene().pop_stacking_context(); - // } - // } - - // if overflowing { - // cx.scene().pop_layer(); - // } - // } - - // fn rect_for_text_range( - // &self, - // range_utf16: Range, - // _: Bounds, - // _: Bounds, - // _: &Self::LayoutState, - // _: &Self::PaintState, - // view: &Workspace, - // cx: &ViewContext, - // ) -> Option> { - // self.children - // .iter() - // .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx)) - // } - - // fn debug( - // &self, - // bounds: Bounds, - // _: &Self::LayoutState, - // _: &Self::PaintState, - // view: &Workspace, - // cx: &ViewContext, - // ) -> json::Value { - // serde_json::json!({ - // "type": "PaneAxis", - // "bounds": bounds.to_json(), - // "axis": self.axis.to_json(), - // "flexes": *self.flexes.borrow(), - // "children": self.children.iter().map(|child| child.debug(view, cx)).collect::>() - // }) - // } - // } } diff --git a/crates/workspace2/src/searchable.rs b/crates/workspace2/src/searchable.rs index eadd602c84..59202cbbaf 100644 --- a/crates/workspace2/src/searchable.rs +++ b/crates/workspace2/src/searchable.rs @@ -193,7 +193,7 @@ impl SearchableItemHandle for View { cx: &mut WindowContext, ) -> Task>> { let matches = self.update(cx, |this, cx| this.find_matches(query, cx)); - cx.spawn(|cx| async { + cx.spawn(|_| async { let matches = matches.await; matches .into_iter() @@ -253,7 +253,7 @@ pub trait WeakSearchableItemHandle: WeakItemHandle { } impl WeakSearchableItemHandle for WeakView { - fn upgrade(&self, cx: &AppContext) -> Option> { + fn upgrade(&self, _cx: &AppContext) -> Option> { Some(Box::new(self.upgrade()?)) } diff --git a/crates/workspace2/src/status_bar.rs b/crates/workspace2/src/status_bar.rs index c0cbd127ac..ba571d6e0a 100644 --- a/crates/workspace2/src/status_bar.rs +++ b/crates/workspace2/src/status_bar.rs @@ -51,14 +51,14 @@ impl Render for StatusBar { } impl StatusBar { - fn render_left_tools(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_left_tools(&self, _: &mut ViewContext) -> impl IntoElement { h_stack() .items_center() .gap_2() .children(self.left_items.iter().map(|item| item.to_any())) } - fn render_right_tools(&self, cx: &mut ViewContext) -> impl IntoElement { + fn render_right_tools(&self, _: &mut ViewContext) -> impl IntoElement { h_stack() .items_center() .gap_2() diff --git a/crates/workspace2/src/toolbar.rs b/crates/workspace2/src/toolbar.rs index b6d7b3e2cb..a6c8f9d0bf 100644 --- a/crates/workspace2/src/toolbar.rs +++ b/crates/workspace2/src/toolbar.rs @@ -109,8 +109,22 @@ impl Render for Toolbar { .child( h_stack() .justify_between() - .child(h_stack().children(self.left_items().map(|item| item.to_any()))) - .child(h_stack().children(self.right_items().map(|item| item.to_any()))), + .when(self.left_items().count() > 0, |this| { + this.child( + h_stack() + .flex_1() + .justify_start() + .children(self.left_items().map(|item| item.to_any())), + ) + }) + .when(self.right_items().count() > 0, |this| { + this.child( + h_stack() + .flex_1() + .justify_end() + .children(self.right_items().map(|item| item.to_any())), + ) + }), ) .children(secondary_item) } diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index a07c5818a0..3e92469029 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -1,15 +1,11 @@ -#![allow(unused_variables, dead_code, unused_mut)] -// todo!() this is to make transition easier. - pub mod dock; pub mod item; +mod modal_layer; pub mod notifications; pub mod pane; pub mod pane_group; mod persistence; pub mod searchable; -// todo!() -mod modal_layer; pub mod shared_screen; mod status_bar; mod toolbar; @@ -236,14 +232,14 @@ pub fn init(app_state: Arc, cx: &mut AppContext) { cx.on_action({ let app_state = Arc::downgrade(&app_state); move |_: &Open, cx: &mut AppContext| { - let mut paths = cx.prompt_for_paths(PathPromptOptions { + let paths = cx.prompt_for_paths(PathPromptOptions { files: true, directories: true, multiple: true, }); if let Some(app_state) = app_state.upgrade() { - cx.spawn(move |mut cx| async move { + cx.spawn(move |cx| async move { if let Some(paths) = paths.await.log_err().flatten() { cx.update(|cx| { open_paths(&paths, &app_state, None, cx).detach_and_log_err(cx) @@ -458,7 +454,7 @@ pub struct Workspace { leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>, database_id: WorkspaceId, app_state: Arc, - subscriptions: Vec, + _subscriptions: Vec, _apply_leader_updates: Task>, _observe_current_user: Task>, _schedule_serialize: Option>, @@ -590,12 +586,9 @@ impl Workspace { let left_dock = cx.build_view(|cx| Dock::new(DockPosition::Left, cx)); let bottom_dock = cx.build_view(|cx| Dock::new(DockPosition::Bottom, cx)); let right_dock = cx.build_view(|cx| Dock::new(DockPosition::Right, cx)); - let left_dock_buttons = - cx.build_view(|cx| PanelButtons::new(left_dock.clone(), weak_handle.clone(), cx)); - let bottom_dock_buttons = - cx.build_view(|cx| PanelButtons::new(bottom_dock.clone(), weak_handle.clone(), cx)); - let right_dock_buttons = - cx.build_view(|cx| PanelButtons::new(right_dock.clone(), weak_handle.clone(), cx)); + let left_dock_buttons = cx.build_view(|cx| PanelButtons::new(left_dock.clone(), cx)); + let bottom_dock_buttons = cx.build_view(|cx| PanelButtons::new(bottom_dock.clone(), cx)); + let right_dock_buttons = cx.build_view(|cx| PanelButtons::new(right_dock.clone(), cx)); let status_bar = cx.build_view(|cx| { let mut status_bar = StatusBar::new(¢er_pane.clone(), cx); status_bar.add_left_item(left_dock_buttons, cx); @@ -604,8 +597,7 @@ impl Workspace { status_bar }); - let workspace_handle = cx.view().downgrade(); - let modal_layer = cx.build_view(|cx| ModalLayer::new()); + let modal_layer = cx.build_view(|_| ModalLayer::new()); // todo!() // cx.update_default_global::, _, _>(|drag_and_drop, _| { @@ -703,7 +695,7 @@ impl Workspace { _apply_leader_updates, _schedule_serialize: None, leader_updates_tx, - subscriptions, + _subscriptions: subscriptions, pane_history_timestamp, workspace_actions: Default::default(), // This data will be incorrect, but it will be overwritten by the time it needs to be used. @@ -763,7 +755,7 @@ impl Workspace { }; let window = if let Some(window) = requesting_window { - cx.update_window(window.into(), |old_workspace, cx| { + cx.update_window(window.into(), |_, cx| { cx.replace_root_view(|cx| { Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx) }); @@ -1185,8 +1177,7 @@ impl Workspace { } fn save_all(&mut self, action: &SaveAll, cx: &mut ViewContext) { - let save_all = self - .save_all_internal(action.save_intent.unwrap_or(SaveIntent::SaveAll), cx) + self.save_all_internal(action.save_intent.unwrap_or(SaveIntent::SaveAll), cx) .detach_and_log_err(cx); } @@ -1216,7 +1207,7 @@ impl Workspace { cx.spawn(|workspace, mut cx| async move { // Override save mode and display "Save all files" prompt if save_intent == SaveIntent::Close && dirty_items.len() > 1 { - let mut answer = workspace.update(&mut cx, |_, cx| { + let answer = workspace.update(&mut cx, |_, cx| { let prompt = Pane::file_names_for_prompt( &mut dirty_items.iter().map(|(_, handle)| handle), dirty_items.len(), @@ -1261,7 +1252,7 @@ impl Workspace { } pub fn open(&mut self, _: &Open, cx: &mut ViewContext) { - let mut paths = cx.prompt_for_paths(PathPromptOptions { + let paths = cx.prompt_for_paths(PathPromptOptions { files: true, directories: true, multiple: true, @@ -1390,7 +1381,7 @@ impl Workspace { } fn add_folder_to_project(&mut self, _: &AddFolderToProject, cx: &mut ViewContext) { - let mut paths = cx.prompt_for_paths(PathPromptOptions { + let paths = cx.prompt_for_paths(PathPromptOptions { files: false, directories: true, multiple: true, @@ -1670,6 +1661,8 @@ impl Workspace { None } + // todo!("implement zoom") + #[allow(unused)] fn zoom_out(&mut self, cx: &mut ViewContext) { for pane in &self.panes { pane.update(cx, |pane, cx| pane.set_zoomed(false, cx)); @@ -2043,20 +2036,20 @@ impl Workspace { _ => bounding_box.center(), }; - let distance_to_next = 1.; //todo(pane dividers styling) + let distance_to_next = 8.; //todo(pane dividers styling) let target = match direction { SplitDirection::Left => { - Point::new(bounding_box.origin.x - distance_to_next.into(), center.y) + Point::new(bounding_box.left() - distance_to_next.into(), center.y) } SplitDirection::Right => { Point::new(bounding_box.right() + distance_to_next.into(), center.y) } SplitDirection::Up => { - Point::new(center.x, bounding_box.origin.y - distance_to_next.into()) + Point::new(center.x, bounding_box.top() - distance_to_next.into()) } SplitDirection::Down => { - Point::new(center.x, bounding_box.top() + distance_to_next.into()) + Point::new(center.x, bounding_box.bottom() + distance_to_next.into()) } }; self.center.pane_at_pixel_position(target) @@ -2574,7 +2567,7 @@ impl Workspace { // } // } - fn render_notifications(&self, cx: &ViewContext) -> Option
{ + fn render_notifications(&self, _cx: &ViewContext) -> Option
{ if self.notifications.is_empty() { None } else { @@ -3005,6 +2998,7 @@ impl Workspace { cx.notify(); } + #[allow(unused)] fn schedule_serialize(&mut self, cx: &mut ViewContext) { self._schedule_serialize = Some(cx.spawn(|this, mut cx| async move { cx.background_executor() @@ -3143,12 +3137,7 @@ impl Workspace { cx: &mut ViewContext, ) -> Task>>>> { cx.spawn(|workspace, mut cx| async move { - let (project, old_center_pane) = workspace.update(&mut cx, |workspace, _| { - ( - workspace.project().clone(), - workspace.last_active_center_pane.clone(), - ) - })?; + let project = workspace.update(&mut cx, |workspace, _| workspace.project().clone())?; let mut center_group = None; let mut center_items = None; @@ -3293,7 +3282,7 @@ impl Workspace { .on_action(cx.listener(|workspace, action: &SwapPaneInDirection, cx| { workspace.swap_pane_in_direction(action.0, cx) })) - .on_action(cx.listener(|this, e: &ToggleLeftDock, cx| { + .on_action(cx.listener(|this, _: &ToggleLeftDock, cx| { this.toggle_dock(DockPosition::Left, cx); })) .on_action( @@ -3313,42 +3302,12 @@ impl Workspace { ) .on_action(cx.listener(Workspace::open)) .on_action(cx.listener(Workspace::close_window)) - - // cx.add_action(Workspace::activate_pane_at_index); - // cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| { - // workspace.reopen_closed_item(cx).detach(); - // }); - // cx.add_action(|workspace: &mut Workspace, _: &GoBack, cx| { - // workspace - // .go_back(workspace.active_pane().downgrade(), cx) - // .detach(); - // }); - // cx.add_action(|workspace: &mut Workspace, _: &GoForward, cx| { - // workspace - // .go_forward(workspace.active_pane().downgrade(), cx) - // .detach(); - // }); - - // cx.add_action(|_: &mut Workspace, _: &install_cli::Install, cx| { - // cx.spawn(|workspace, mut cx| async move { - // let err = install_cli::install_cli(&cx) - // .await - // .context("Failed to create CLI symlink"); - - // workspace.update(&mut cx, |workspace, cx| { - // if matches!(err, Err(_)) { - // err.notify_err(workspace, cx); - // } else { - // workspace.show_notification(1, cx, |cx| { - // cx.build_view(|_| { - // MessageNotification::new("Successfully installed the `zed` binary") - // }) - // }); - // } - // }) - // }) - // .detach(); - // }); + .on_action(cx.listener(Workspace::activate_pane_at_index)) + .on_action( + cx.listener(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| { + workspace.reopen_closed_item(cx).detach(); + }), + ) } #[cfg(any(test, feature = "test-support"))] @@ -3418,7 +3377,7 @@ impl Workspace { self } - fn add_workspace_actions_listeners(&self, mut div: Div, cx: &mut ViewContext) -> Div { + fn add_workspace_actions_listeners(&self, div: Div, cx: &mut ViewContext) -> Div { let mut div = div .on_action(cx.listener(Self::close_inactive_items_and_panes)) .on_action(cx.listener(Self::close_all_items_and_panes)) @@ -3578,9 +3537,7 @@ impl FocusableView for Workspace { } } -struct WorkspaceBounds(Bounds); - -#[derive(Render)] +#[derive(Clone, Render)] struct DraggedDock(DockPosition); impl Render for Workspace { @@ -3628,7 +3585,7 @@ impl Render for Workspace { .border_b() .border_color(cx.theme().colors().border) .child( - canvas(cx.listener(|workspace, bounds, cx| { + canvas(cx.listener(|workspace, bounds, _| { workspace.bounds = *bounds; })) .absolute() @@ -3636,7 +3593,7 @@ impl Render for Workspace { ) .on_drag_move( cx.listener(|workspace, e: &DragMoveEvent, cx| { - match e.drag.read(cx).0 { + match e.drag(cx).0 { DockPosition::Left => { let size = workspace.bounds.left() + e.event.position.x; workspace.left_dock.update(cx, |left_dock, cx| { @@ -4056,7 +4013,7 @@ async fn join_channel_internal( active_call: &Model, cx: &mut AsyncAppContext, ) -> Result { - let (should_prompt, open_room) = active_call.read_with(cx, |active_call, cx| { + let (should_prompt, open_room) = active_call.update(cx, |active_call, cx| { let Some(room) = active_call.room().map(|room| room.read(cx)) else { return (false, None); }; @@ -4421,7 +4378,7 @@ pub fn restart(_: &Restart, cx: &mut AppContext) { } cx.spawn(|mut cx| async move { - if let Some(mut prompt) = prompt { + if let Some(prompt) = prompt { let answer = prompt.await?; if answer != 0 { return Ok(()); @@ -4460,6 +4417,8 @@ fn parse_pixel_size_env_var(value: &str) -> Option> { #[cfg(test)] mod tests { + use std::{cell::RefCell, rc::Rc}; + use super::*; use crate::item::{ test::{TestItem, TestProjectItem}, @@ -4470,7 +4429,6 @@ mod tests { use project::{Project, ProjectEntryId}; use serde_json::json; use settings::SettingsStore; - use std::{cell::RefCell, rc::Rc}; #[gpui::test] async fn test_tab_disambiguation(cx: &mut TestAppContext) { @@ -4544,7 +4502,7 @@ mod tests { let project = Project::test(fs, ["root1".as_ref()], cx).await; let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx)); let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone()); - let worktree_id = project.read_with(cx, |project, cx| { + let worktree_id = project.update(cx, |project, cx| { project.worktrees().next().unwrap().read(cx).id() }); @@ -4557,7 +4515,7 @@ mod tests { // Add an item to an empty pane workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item1), cx)); - project.read_with(cx, |project, cx| { + project.update(cx, |project, cx| { assert_eq!( project.active_entry(), project @@ -4570,7 +4528,7 @@ mod tests { // Add a second item to a non-empty pane workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item2), cx)); assert_eq!(cx.window_title().as_deref(), Some("two.txt — root1")); - project.read_with(cx, |project, cx| { + project.update(cx, |project, cx| { assert_eq!( project.active_entry(), project @@ -4586,7 +4544,7 @@ mod tests { .await .unwrap(); assert_eq!(cx.window_title().as_deref(), Some("one.txt — root1")); - project.read_with(cx, |project, cx| { + project.update(cx, |project, cx| { assert_eq!( project.active_entry(), project @@ -4970,14 +4928,14 @@ mod tests { item.is_dirty = true; cx.blur(); }); - cx.executor().run_until_parked(); + cx.run_until_parked(); item.update(cx, |item, _| assert_eq!(item.save_count, 5)); // Ensure autosave is prevented for deleted files also when closing the buffer. let _close_items = pane.update(cx, |pane, cx| { pane.close_items(cx, SaveIntent::Close, move |id| id == item_id) }); - cx.executor().run_until_parked(); + cx.run_until_parked(); assert!(cx.has_pending_prompt()); item.update(cx, |item, _| assert_eq!(item.save_count, 5)); } @@ -5036,363 +4994,362 @@ mod tests { }); } - // #[gpui::test] - // async fn test_toggle_docks_and_panels(cx: &mut gpui::TestAppContext) { - // init_test(cx); - // let fs = FakeFs::new(cx.executor()); + // #[gpui::test] + // async fn test_toggle_docks_and_panels(cx: &mut gpui::TestAppContext) { + // init_test(cx); + // let fs = FakeFs::new(cx.executor()); - // let project = Project::test(fs, [], cx).await; - // let window = cx.add_window(|cx| Workspace::test_new(project, cx)); - // let workspace = window.root(cx); + // let project = Project::test(fs, [], cx).await; + // let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project, cx)); - // let panel = workspace.update(cx, |workspace, cx| { - // let panel = cx.build_view(|_| TestPanel::new(DockPosition::Right)); - // workspace.add_panel(panel.clone(), cx); + // let panel = workspace.update(cx, |workspace, cx| { + // let panel = cx.build_view(|cx| TestPanel::new(DockPosition::Right, cx)); + // workspace.add_panel(panel.clone(), cx); + // workspace + // .right_dock() + // .update(cx, |right_dock, cx| right_dock.set_open(true, cx)); + + // panel + // }); + + // let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone()); + // pane.update(cx, |pane, cx| { + // let item = cx.build_view(|cx| TestItem::new(cx)); + // pane.add_item(Box::new(item), true, true, None, cx); + // }); + + // // Transfer focus from center to panel + // workspace.update(cx, |workspace, cx| { + // workspace.toggle_panel_focus::(cx); + // }); + + // workspace.update(cx, |workspace, cx| { + // assert!(workspace.right_dock().read(cx).is_open()); + // assert!(!panel.is_zoomed(cx)); + // assert!(panel.read(cx).focus_handle(cx).contains_focused(cx)); + // }); + + // // Transfer focus from panel to center + // workspace.update(cx, |workspace, cx| { + // workspace.toggle_panel_focus::(cx); + // }); + + // workspace.update(cx, |workspace, cx| { + // assert!(workspace.right_dock().read(cx).is_open()); + // assert!(!panel.is_zoomed(cx)); + // assert!(!panel.read(cx).focus_handle(cx).contains_focused(cx)); + // }); + + // // Close the dock + // workspace.update(cx, |workspace, cx| { + // workspace.toggle_dock(DockPosition::Right, cx); + // }); + + // workspace.update(cx, |workspace, cx| { + // assert!(!workspace.right_dock().read(cx).is_open()); + // assert!(!panel.is_zoomed(cx)); + // assert!(!panel.read(cx).focus_handle(cx).contains_focused(cx)); + // }); + + // // Open the dock + // workspace.update(cx, |workspace, cx| { + // workspace.toggle_dock(DockPosition::Right, cx); + // }); + + // workspace.update(cx, |workspace, cx| { + // assert!(workspace.right_dock().read(cx).is_open()); + // assert!(!panel.is_zoomed(cx)); + // assert!(panel.read(cx).focus_handle(cx).contains_focused(cx)); + // }); + + // // Focus and zoom panel + // panel.update(cx, |panel, cx| { + // cx.focus_self(); + // panel.set_zoomed(true, cx) + // }); + + // workspace.update(cx, |workspace, cx| { + // assert!(workspace.right_dock().read(cx).is_open()); + // assert!(panel.is_zoomed(cx)); + // assert!(panel.read(cx).focus_handle(cx).contains_focused(cx)); + // }); + + // // Transfer focus to the center closes the dock + // workspace.update(cx, |workspace, cx| { + // workspace.toggle_panel_focus::(cx); + // }); + + // workspace.update(cx, |workspace, cx| { + // assert!(!workspace.right_dock().read(cx).is_open()); + // assert!(panel.is_zoomed(cx)); + // assert!(!panel.read(cx).focus_handle(cx).contains_focused(cx)); + // }); + + // // Transferring focus back to the panel keeps it zoomed + // workspace.update(cx, |workspace, cx| { + // workspace.toggle_panel_focus::(cx); + // }); + + // workspace.update(cx, |workspace, cx| { + // assert!(workspace.right_dock().read(cx).is_open()); + // assert!(panel.is_zoomed(cx)); + // assert!(panel.read(cx).focus_handle(cx).contains_focused(cx)); + // }); + + // // Close the dock while it is zoomed + // workspace.update(cx, |workspace, cx| { + // workspace.toggle_dock(DockPosition::Right, cx) + // }); + + // workspace.update(cx, |workspace, cx| { + // assert!(!workspace.right_dock().read(cx).is_open()); + // assert!(panel.is_zoomed(cx)); + // assert!(workspace.zoomed.is_none()); + // assert!(!panel.read(cx).focus_handle(cx).contains_focused(cx)); + // }); + + // // Opening the dock, when it's zoomed, retains focus + // workspace.update(cx, |workspace, cx| { + // workspace.toggle_dock(DockPosition::Right, cx) + // }); + + // workspace.update(cx, |workspace, cx| { + // assert!(workspace.right_dock().read(cx).is_open()); + // assert!(panel.is_zoomed(cx)); + // assert!(workspace.zoomed.is_some()); + // assert!(panel.read(cx).focus_handle(cx).contains_focused(cx)); + // }); + + // // Unzoom and close the panel, zoom the active pane. + // panel.update(cx, |panel, cx| panel.set_zoomed(false, cx)); + // workspace.update(cx, |workspace, cx| { + // workspace.toggle_dock(DockPosition::Right, cx) + // }); + // pane.update(cx, |pane, cx| pane.toggle_zoom(&Default::default(), cx)); + + // // Opening a dock unzooms the pane. + // workspace.update(cx, |workspace, cx| { + // workspace.toggle_dock(DockPosition::Right, cx) + // }); + // workspace.update(cx, |workspace, cx| { + // let pane = pane.read(cx); + // assert!(!pane.is_zoomed()); + // assert!(!pane.focus_handle(cx).is_focused(cx)); + // assert!(workspace.right_dock().read(cx).is_open()); + // assert!(workspace.zoomed.is_none()); + // }); + // } + + // #[gpui::test] + // async fn test_panels(cx: &mut gpui::TestAppContext) { + // init_test(cx); + // let fs = FakeFs::new(cx.executor()); + + // let project = Project::test(fs, [], cx).await; + // let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project, cx)); + + // let (panel_1, panel_2) = workspace.update(cx, |workspace, cx| { + // // Add panel_1 on the left, panel_2 on the right. + // let panel_1 = cx.build_view(|cx| TestPanel::new(DockPosition::Left, cx)); + // workspace.add_panel(panel_1.clone(), cx); + // workspace + // .left_dock() + // .update(cx, |left_dock, cx| left_dock.set_open(true, cx)); + // let panel_2 = cx.build_view(|cx| TestPanel::new(DockPosition::Right, cx)); + // workspace.add_panel(panel_2.clone(), cx); + // workspace + // .right_dock() + // .update(cx, |right_dock, cx| right_dock.set_open(true, cx)); + + // let left_dock = workspace.left_dock(); + // assert_eq!( + // left_dock.read(cx).visible_panel().unwrap().panel_id(), + // panel_1.panel_id() + // ); + // assert_eq!( + // left_dock.read(cx).active_panel_size(cx).unwrap(), + // panel_1.size(cx) + // ); + + // left_dock.update(cx, |left_dock, cx| { + // left_dock.resize_active_panel(Some(1337.), cx) + // }); + // assert_eq!( // workspace // .right_dock() - // .update(cx, |right_dock, cx| right_dock.set_open(true, cx)); + // .read(cx) + // .visible_panel() + // .unwrap() + // .panel_id(), + // panel_2.panel_id(), + // ); - // panel - // }); + // (panel_1, panel_2) + // }); - // let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone()); - // pane.update(cx, |pane, cx| { - // let item = cx.build_view(|_| TestItem::new(cx)); - // pane.add_item(Box::new(item), true, true, None, cx); - // }); + // // Move panel_1 to the right + // panel_1.update(cx, |panel_1, cx| { + // panel_1.set_position(DockPosition::Right, cx) + // }); - // // Transfer focus from center to panel - // workspace.update(cx, |workspace, cx| { - // workspace.toggle_panel_focus::(cx); - // }); + // workspace.update(cx, |workspace, cx| { + // // Since panel_1 was visible on the left, it should now be visible now that it's been moved to the right. + // // Since it was the only panel on the left, the left dock should now be closed. + // assert!(!workspace.left_dock().read(cx).is_open()); + // assert!(workspace.left_dock().read(cx).visible_panel().is_none()); + // let right_dock = workspace.right_dock(); + // assert_eq!( + // right_dock.read(cx).visible_panel().unwrap().panel_id(), + // panel_1.panel_id() + // ); + // assert_eq!(right_dock.read(cx).active_panel_size(cx).unwrap(), 1337.); - // workspace.update(cx, |workspace, cx| { - // assert!(workspace.right_dock().read(cx).is_open()); - // assert!(!panel.is_zoomed(cx)); - // assert!(panel.has_focus(cx)); - // }); + // // Now we move panel_2 to the left + // panel_2.set_position(DockPosition::Left, cx); + // }); - // // Transfer focus from panel to center - // workspace.update(cx, |workspace, cx| { - // workspace.toggle_panel_focus::(cx); - // }); - - // workspace.update(cx, |workspace, cx| { - // assert!(workspace.right_dock().read(cx).is_open()); - // assert!(!panel.is_zoomed(cx)); - // assert!(!panel.has_focus(cx)); - // }); - - // // Close the dock - // workspace.update(cx, |workspace, cx| { - // workspace.toggle_dock(DockPosition::Right, cx); - // }); - - // workspace.update(cx, |workspace, cx| { - // assert!(!workspace.right_dock().read(cx).is_open()); - // assert!(!panel.is_zoomed(cx)); - // assert!(!panel.has_focus(cx)); - // }); - - // // Open the dock - // workspace.update(cx, |workspace, cx| { - // workspace.toggle_dock(DockPosition::Right, cx); - // }); - - // workspace.update(cx, |workspace, cx| { - // assert!(workspace.right_dock().read(cx).is_open()); - // assert!(!panel.is_zoomed(cx)); - // assert!(panel.has_focus(cx)); - // }); - - // // Focus and zoom panel - // panel.update(cx, |panel, cx| { - // cx.focus_self(); - // panel.set_zoomed(true, cx) - // }); - - // workspace.update(cx, |workspace, cx| { - // assert!(workspace.right_dock().read(cx).is_open()); - // assert!(panel.is_zoomed(cx)); - // assert!(panel.has_focus(cx)); - // }); - - // // Transfer focus to the center closes the dock - // workspace.update(cx, |workspace, cx| { - // workspace.toggle_panel_focus::(cx); - // }); - - // workspace.update(cx, |workspace, cx| { - // assert!(!workspace.right_dock().read(cx).is_open()); - // assert!(panel.is_zoomed(cx)); - // assert!(!panel.has_focus(cx)); - // }); - - // // Transferring focus back to the panel keeps it zoomed - // workspace.update(cx, |workspace, cx| { - // workspace.toggle_panel_focus::(cx); - // }); - - // workspace.update(cx, |workspace, cx| { - // assert!(workspace.right_dock().read(cx).is_open()); - // assert!(panel.is_zoomed(cx)); - // assert!(panel.has_focus(cx)); - // }); - - // // Close the dock while it is zoomed - // workspace.update(cx, |workspace, cx| { - // workspace.toggle_dock(DockPosition::Right, cx) - // }); - - // workspace.update(cx, |workspace, cx| { - // assert!(!workspace.right_dock().read(cx).is_open()); - // assert!(panel.is_zoomed(cx)); - // assert!(workspace.zoomed.is_none()); - // assert!(!panel.has_focus(cx)); - // }); - - // // Opening the dock, when it's zoomed, retains focus - // workspace.update(cx, |workspace, cx| { - // workspace.toggle_dock(DockPosition::Right, cx) - // }); - - // workspace.update(cx, |workspace, cx| { - // assert!(workspace.right_dock().read(cx).is_open()); - // assert!(panel.is_zoomed(cx)); - // assert!(workspace.zoomed.is_some()); - // assert!(panel.has_focus(cx)); - // }); - - // // Unzoom and close the panel, zoom the active pane. - // panel.update(cx, |panel, cx| panel.set_zoomed(false, cx)); - // workspace.update(cx, |workspace, cx| { - // workspace.toggle_dock(DockPosition::Right, cx) - // }); - // pane.update(cx, |pane, cx| pane.toggle_zoom(&Default::default(), cx)); - - // // Opening a dock unzooms the pane. - // workspace.update(cx, |workspace, cx| { - // workspace.toggle_dock(DockPosition::Right, cx) - // }); - // workspace.update(cx, |workspace, cx| { - // let pane = pane.read(cx); - // assert!(!pane.is_zoomed()); - // assert!(!pane.has_focus()); - // assert!(workspace.right_dock().read(cx).is_open()); - // assert!(workspace.zoomed.is_none()); - // }); - // } - - // #[gpui::test] - // async fn test_panels(cx: &mut gpui::TestAppContext) { - // init_test(cx); - // let fs = FakeFs::new(cx.executor()); - - // let project = Project::test(fs, [], cx).await; - // let window = cx.add_window(|cx| Workspace::test_new(project, cx)); - // let workspace = window.root(cx); - - // let (panel_1, panel_2) = workspace.update(cx, |workspace, cx| { - // // Add panel_1 on the left, panel_2 on the right. - // let panel_1 = cx.build_view(|_| TestPanel::new(DockPosition::Left)); - // workspace.add_panel(panel_1.clone(), cx); - // workspace - // .left_dock() - // .update(cx, |left_dock, cx| left_dock.set_open(true, cx)); - // let panel_2 = cx.build_view(|_| TestPanel::new(DockPosition::Right)); - // workspace.add_panel(panel_2.clone(), cx); + // workspace.update(cx, |workspace, cx| { + // // Since panel_2 was not visible on the right, we don't open the left dock. + // assert!(!workspace.left_dock().read(cx).is_open()); + // // And the right dock is unaffected in it's displaying of panel_1 + // assert!(workspace.right_dock().read(cx).is_open()); + // assert_eq!( // workspace // .right_dock() - // .update(cx, |right_dock, cx| right_dock.set_open(true, cx)); + // .read(cx) + // .visible_panel() + // .unwrap() + // .panel_id(), + // panel_1.panel_id(), + // ); + // }); - // let left_dock = workspace.left_dock(); - // assert_eq!( - // left_dock.read(cx).visible_panel().unwrap().id(), - // panel_1.id() - // ); - // assert_eq!( - // left_dock.read(cx).active_panel_size(cx).unwrap(), - // panel_1.size(cx) - // ); + // // Move panel_1 back to the left + // panel_1.update(cx, |panel_1, cx| { + // panel_1.set_position(DockPosition::Left, cx) + // }); - // left_dock.update(cx, |left_dock, cx| { - // left_dock.resize_active_panel(Some(1337.), cx) - // }); - // assert_eq!( - // workspace - // .right_dock() - // .read(cx) - // .visible_panel() - // .unwrap() - // .id(), - // panel_2.id() - // ); + // workspace.update(cx, |workspace, cx| { + // // Since panel_1 was visible on the right, we open the left dock and make panel_1 active. + // let left_dock = workspace.left_dock(); + // assert!(left_dock.read(cx).is_open()); + // assert_eq!( + // left_dock.read(cx).visible_panel().unwrap().panel_id(), + // panel_1.panel_id() + // ); + // assert_eq!(left_dock.read(cx).active_panel_size(cx).unwrap(), 1337.); + // // And right the dock should be closed as it no longer has any panels. + // assert!(!workspace.right_dock().read(cx).is_open()); - // (panel_1, panel_2) - // }); + // // Now we move panel_1 to the bottom + // panel_1.set_position(DockPosition::Bottom, cx); + // }); - // // Move panel_1 to the right - // panel_1.update(cx, |panel_1, cx| { - // panel_1.set_position(DockPosition::Right, cx) - // }); + // workspace.update(cx, |workspace, cx| { + // // Since panel_1 was visible on the left, we close the left dock. + // assert!(!workspace.left_dock().read(cx).is_open()); + // // The bottom dock is sized based on the panel's default size, + // // since the panel orientation changed from vertical to horizontal. + // let bottom_dock = workspace.bottom_dock(); + // assert_eq!( + // bottom_dock.read(cx).active_panel_size(cx).unwrap(), + // panel_1.size(cx), + // ); + // // Close bottom dock and move panel_1 back to the left. + // bottom_dock.update(cx, |bottom_dock, cx| bottom_dock.set_open(false, cx)); + // panel_1.set_position(DockPosition::Left, cx); + // }); - // workspace.update(cx, |workspace, cx| { - // // Since panel_1 was visible on the left, it should now be visible now that it's been moved to the right. - // // Since it was the only panel on the left, the left dock should now be closed. - // assert!(!workspace.left_dock().read(cx).is_open()); - // assert!(workspace.left_dock().read(cx).visible_panel().is_none()); - // let right_dock = workspace.right_dock(); - // assert_eq!( - // right_dock.read(cx).visible_panel().unwrap().id(), - // panel_1.id() - // ); - // assert_eq!(right_dock.read(cx).active_panel_size(cx).unwrap(), 1337.); + // // Emit activated event on panel 1 + // panel_1.update(cx, |_, cx| cx.emit(PanelEvent::Activate)); - // // Now we move panel_2 to the left - // panel_2.set_position(DockPosition::Left, cx); - // }); + // // Now the left dock is open and panel_1 is active and focused. + // workspace.update(cx, |workspace, cx| { + // let left_dock = workspace.left_dock(); + // assert!(left_dock.read(cx).is_open()); + // assert_eq!( + // left_dock.read(cx).visible_panel().unwrap().panel_id(), + // panel_1.panel_id(), + // ); + // assert!(panel_1.focus_handle(cx).is_focused(cx)); + // }); - // workspace.update(cx, |workspace, cx| { - // // Since panel_2 was not visible on the right, we don't open the left dock. - // assert!(!workspace.left_dock().read(cx).is_open()); - // // And the right dock is unaffected in it's displaying of panel_1 - // assert!(workspace.right_dock().read(cx).is_open()); - // assert_eq!( - // workspace - // .right_dock() - // .read(cx) - // .visible_panel() - // .unwrap() - // .id(), - // panel_1.id() - // ); - // }); + // // Emit closed event on panel 2, which is not active + // panel_2.update(cx, |_, cx| cx.emit(PanelEvent::Close)); - // // Move panel_1 back to the left - // panel_1.update(cx, |panel_1, cx| { - // panel_1.set_position(DockPosition::Left, cx) - // }); + // // Wo don't close the left dock, because panel_2 wasn't the active panel + // workspace.update(cx, |workspace, cx| { + // let left_dock = workspace.left_dock(); + // assert!(left_dock.read(cx).is_open()); + // assert_eq!( + // left_dock.read(cx).visible_panel().unwrap().panel_id(), + // panel_1.panel_id(), + // ); + // }); - // workspace.update(cx, |workspace, cx| { - // // Since panel_1 was visible on the right, we open the left dock and make panel_1 active. - // let left_dock = workspace.left_dock(); - // assert!(left_dock.read(cx).is_open()); - // assert_eq!( - // left_dock.read(cx).visible_panel().unwrap().id(), - // panel_1.id() - // ); - // assert_eq!(left_dock.read(cx).active_panel_size(cx).unwrap(), 1337.); - // // And right the dock should be closed as it no longer has any panels. - // assert!(!workspace.right_dock().read(cx).is_open()); + // // Emitting a ZoomIn event shows the panel as zoomed. + // panel_1.update(cx, |_, cx| cx.emit(PanelEvent::ZoomIn)); + // workspace.update(cx, |workspace, _| { + // assert_eq!(workspace.zoomed, Some(panel_1.to_any().downgrade())); + // assert_eq!(workspace.zoomed_position, Some(DockPosition::Left)); + // }); - // // Now we move panel_1 to the bottom - // panel_1.set_position(DockPosition::Bottom, cx); - // }); + // // Move panel to another dock while it is zoomed + // panel_1.update(cx, |panel, cx| panel.set_position(DockPosition::Right, cx)); + // workspace.update(cx, |workspace, _| { + // assert_eq!(workspace.zoomed, Some(panel_1.to_any().downgrade())); - // workspace.update(cx, |workspace, cx| { - // // Since panel_1 was visible on the left, we close the left dock. - // assert!(!workspace.left_dock().read(cx).is_open()); - // // The bottom dock is sized based on the panel's default size, - // // since the panel orientation changed from vertical to horizontal. - // let bottom_dock = workspace.bottom_dock(); - // assert_eq!( - // bottom_dock.read(cx).active_panel_size(cx).unwrap(), - // panel_1.size(cx), - // ); - // // Close bottom dock and move panel_1 back to the left. - // bottom_dock.update(cx, |bottom_dock, cx| bottom_dock.set_open(false, cx)); - // panel_1.set_position(DockPosition::Left, cx); - // }); + // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right)); + // }); - // // Emit activated event on panel 1 - // panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::Activated)); + // // If focus is transferred to another view that's not a panel or another pane, we still show + // // the panel as zoomed. + // let other_focus_handle = cx.update(|cx| cx.focus_handle()); + // cx.update(|cx| cx.focus(&other_focus_handle)); + // workspace.update(cx, |workspace, _| { + // assert_eq!(workspace.zoomed, Some(panel_1.to_any().downgrade())); + // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right)); + // }); - // // Now the left dock is open and panel_1 is active and focused. - // workspace.update(cx, |workspace, cx| { - // let left_dock = workspace.left_dock(); - // assert!(left_dock.read(cx).is_open()); - // assert_eq!( - // left_dock.read(cx).visible_panel().unwrap().id(), - // panel_1.id() - // ); - // assert!(panel_1.is_focused(cx)); - // }); + // // If focus is transferred elsewhere in the workspace, the panel is no longer zoomed. + // workspace.update(cx, |_, cx| cx.focus_self()); + // workspace.update(cx, |workspace, _| { + // assert_eq!(workspace.zoomed, None); + // assert_eq!(workspace.zoomed_position, None); + // }); - // // Emit closed event on panel 2, which is not active - // panel_2.update(cx, |_, cx| cx.emit(TestPanelEvent::Closed)); + // // If focus is transferred again to another view that's not a panel or a pane, we won't + // // show the panel as zoomed because it wasn't zoomed before. + // cx.update(|cx| cx.focus(&other_focus_handle)); + // workspace.update(cx, |workspace, _| { + // assert_eq!(workspace.zoomed, None); + // assert_eq!(workspace.zoomed_position, None); + // }); - // // Wo don't close the left dock, because panel_2 wasn't the active panel - // workspace.update(cx, |workspace, cx| { - // let left_dock = workspace.left_dock(); - // assert!(left_dock.read(cx).is_open()); - // assert_eq!( - // left_dock.read(cx).visible_panel().unwrap().id(), - // panel_1.id() - // ); - // }); + // // When focus is transferred back to the panel, it is zoomed again. + // panel_1.update(cx, |_, cx| cx.focus_self()); + // workspace.update(cx, |workspace, _| { + // assert_eq!(workspace.zoomed, Some(panel_1.to_any().downgrade())); + // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right)); + // }); - // // Emitting a ZoomIn event shows the panel as zoomed. - // panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::ZoomIn)); - // workspace.update(cx, |workspace, _| { - // assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); - // assert_eq!(workspace.zoomed_position, Some(DockPosition::Left)); - // }); + // // Emitting a ZoomOut event unzooms the panel. + // panel_1.update(cx, |_, cx| cx.emit(PanelEvent::ZoomOut)); + // workspace.update(cx, |workspace, _| { + // assert_eq!(workspace.zoomed, None); + // assert_eq!(workspace.zoomed_position, None); + // }); - // // Move panel to another dock while it is zoomed - // panel_1.update(cx, |panel, cx| panel.set_position(DockPosition::Right, cx)); - // workspace.update(cx, |workspace, _| { - // assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); - // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right)); - // }); + // // Emit closed event on panel 1, which is active + // panel_1.update(cx, |_, cx| cx.emit(PanelEvent::Close)); - // // If focus is transferred to another view that's not a panel or another pane, we still show - // // the panel as zoomed. - // let focus_receiver = cx.build_view(|_| EmptyView); - // focus_receiver.update(cx, |_, cx| cx.focus_self()); - // workspace.update(cx, |workspace, _| { - // assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); - // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right)); - // }); - - // // If focus is transferred elsewhere in the workspace, the panel is no longer zoomed. - // workspace.update(cx, |_, cx| cx.focus_self()); - // workspace.update(cx, |workspace, _| { - // assert_eq!(workspace.zoomed, None); - // assert_eq!(workspace.zoomed_position, None); - // }); - - // // If focus is transferred again to another view that's not a panel or a pane, we won't - // // show the panel as zoomed because it wasn't zoomed before. - // focus_receiver.update(cx, |_, cx| cx.focus_self()); - // workspace.update(cx, |workspace, _| { - // assert_eq!(workspace.zoomed, None); - // assert_eq!(workspace.zoomed_position, None); - // }); - - // // When focus is transferred back to the panel, it is zoomed again. - // panel_1.update(cx, |_, cx| cx.focus_self()); - // workspace.update(cx, |workspace, _| { - // assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); - // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right)); - // }); - - // // Emitting a ZoomOut event unzooms the panel. - // panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::ZoomOut)); - // workspace.update(cx, |workspace, _| { - // assert_eq!(workspace.zoomed, None); - // assert_eq!(workspace.zoomed_position, None); - // }); - - // // Emit closed event on panel 1, which is active - // panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::Closed)); - - // // Now the left dock is closed, because panel_1 was the active panel - // workspace.update(cx, |workspace, cx| { - // let right_dock = workspace.right_dock(); - // assert!(!right_dock.read(cx).is_open()); - // }); - // } + // // Now the left dock is closed, because panel_1 was the active panel + // workspace.update(cx, |workspace, cx| { + // let right_dock = workspace.right_dock(); + // assert!(!right_dock.read(cx).is_open()); + // }); + // } pub fn init_test(cx: &mut TestAppContext) { cx.update(|cx| {