From b7712c2f4b4bfb7d464f4a8957e9633a00d26e6f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Nov 2023 11:36:39 +0100 Subject: [PATCH] Fix a todo in workspace --- crates/workspace2/src/pane.rs | 32 +- crates/workspace2/src/workspace2.rs | 487 ++++++++++++++-------------- 2 files changed, 262 insertions(+), 257 deletions(-) diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index 2754df92c3..41fafa0330 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -9,8 +9,8 @@ use crate::{ use anyhow::Result; use collections::{HashMap, HashSet, VecDeque}; use gpui2::{ - AppContext, AsyncWindowContext, Component, Div, EntityId, EventEmitter, Model, PromptLevel, - Render, Task, View, ViewContext, VisualContext, WeakView, WindowContext, + AppContext, AsyncWindowContext, Component, Div, EntityId, EventEmitter, FocusHandle, Model, + PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, WindowContext, }; use parking_lot::Mutex; use project2::{Project, ProjectEntryId, ProjectPath}; @@ -171,6 +171,7 @@ impl fmt::Debug for Event { } pub struct Pane { + focus_handle: FocusHandle, items: Vec>, activation_history: Vec, zoomed: bool, @@ -183,7 +184,6 @@ pub struct Pane { // tab_context_menu: ViewHandle, workspace: WeakView, project: Model, - has_focus: bool, // can_drop: Rc, &WindowContext) -> bool>, // can_split: bool, // render_tab_bar_buttons: Rc) -> AnyElement>, @@ -330,6 +330,7 @@ impl Pane { let handle = cx.view().downgrade(); Self { + focus_handle: cx.focus_handle(), items: Vec::new(), activation_history: Vec::new(), zoomed: false, @@ -353,7 +354,6 @@ impl Pane { // tab_context_menu: cx.add_view(|cx| ContextMenu::new(pane_view_id, cx)), workspace, project, - has_focus: false, // can_drop: Rc::new(|_, _| true), // can_split: true, // render_tab_bar_buttons: Rc::new(move |pane, cx| { @@ -420,8 +420,8 @@ impl Pane { // &self.workspace // } - pub fn has_focus(&self) -> bool { - self.has_focus + pub fn has_focus(&self, cx: &WindowContext) -> bool { + self.focus_handle.contains_focused(cx) } // pub fn active_item_index(&self) -> usize { @@ -1020,7 +1020,7 @@ impl Pane { // to activating the item to the left .unwrap_or_else(|| item_index.min(self.items.len()).saturating_sub(1)); - let should_activate = activate_pane || self.has_focus; + let should_activate = activate_pane || self.has_focus(cx); self.activate_item(index_to_activate, should_activate, should_activate, cx); } @@ -1184,6 +1184,10 @@ impl Pane { } } + pub fn focus(&mut self, cx: &mut ViewContext) { + cx.focus(&self.focus_handle); + } + pub fn focus_active_item(&mut self, cx: &mut ViewContext) { if let Some(active_item) = self.active_item() { let focus_handle = active_item.focus_handle(cx); @@ -1865,14 +1869,14 @@ impl Pane { // .into_any() // } - // pub fn set_zoomed(&mut self, zoomed: bool, cx: &mut ViewContext) { - // self.zoomed = zoomed; - // cx.notify(); - // } + pub fn set_zoomed(&mut self, zoomed: bool, cx: &mut ViewContext) { + self.zoomed = zoomed; + cx.notify(); + } - // pub fn is_zoomed(&self) -> bool { - // self.zoomed - // } + pub fn is_zoomed(&self) -> bool { + self.zoomed + } } // impl Entity for Pane { diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index f5f507f3b1..81adebbd65 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -26,7 +26,7 @@ use client2::{ proto::{self, PeerId}, Client, TypedEnvelope, UserStore, }; -use collections::{HashMap, HashSet}; +use collections::{hash_map, HashMap, HashSet}; use dock::{Dock, DockPosition, PanelButtons}; use futures::{ channel::{mpsc, oneshot}, @@ -35,10 +35,10 @@ use futures::{ }; use gpui2::{ div, point, size, AnyModel, AnyView, AnyWeakView, AppContext, AsyncAppContext, - AsyncWindowContext, Bounds, Component, Div, EntityId, EventEmitter, GlobalPixels, Model, - ModelContext, ParentElement, Point, Render, Size, StatefulInteractive, Styled, Subscription, - Task, View, ViewContext, VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle, - WindowOptions, + AsyncWindowContext, Bounds, Component, Div, Entity, EntityId, EventEmitter, FocusHandle, + GlobalPixels, Model, ModelContext, ParentElement, Point, Render, Size, StatefulInteractive, + Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, + WindowContext, WindowHandle, WindowOptions, }; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem}; use language2::LanguageRegistry; @@ -547,9 +547,10 @@ pub enum Event { pub struct Workspace { weak_self: WeakView, + focus_handle: FocusHandle, // modal: Option, zoomed: Option, - // zoomed_position: Option, + zoomed_position: Option, center: PaneGroup, left_dock: View, bottom_dock: View, @@ -766,9 +767,10 @@ impl Workspace { cx.defer(|this, cx| this.update_window_title(cx)); Workspace { weak_self: weak_handle.clone(), + focus_handle: cx.focus_handle(), // modal: None, zoomed: None, - // zoomed_position: None, + zoomed_position: None, center: PaneGroup::new(center_pane.clone()), panes: vec![center_pane.clone()], panes_by_item: Default::default(), @@ -1699,9 +1701,9 @@ impl Workspace { self.active_pane().read(cx).active_item() } - // fn active_project_path(&self, cx: &ViewContext) -> Option { - // self.active_item(cx).and_then(|item| item.project_path(cx)) - // } + fn active_project_path(&self, cx: &ViewContext) -> Option { + self.active_item(cx).and_then(|item| item.project_path(cx)) + } // pub fn save_active_item( // &mut self, @@ -1923,44 +1925,44 @@ impl Workspace { // self.zoomed.and_then(|view| view.upgrade(cx)) // } - // fn dismiss_zoomed_items_to_reveal( - // &mut self, - // dock_to_reveal: Option, - // cx: &mut ViewContext, - // ) { - // // If a center pane is zoomed, unzoom it. - // for pane in &self.panes { - // if pane != &self.active_pane || dock_to_reveal.is_some() { - // pane.update(cx, |pane, cx| pane.set_zoomed(false, cx)); - // } - // } + fn dismiss_zoomed_items_to_reveal( + &mut self, + dock_to_reveal: Option, + cx: &mut ViewContext, + ) { + // If a center pane is zoomed, unzoom it. + for pane in &self.panes { + if pane != &self.active_pane || dock_to_reveal.is_some() { + pane.update(cx, |pane, cx| pane.set_zoomed(false, cx)); + } + } - // // If another dock is zoomed, hide it. - // let mut focus_center = false; - // for dock in [&self.left_dock, &self.right_dock, &self.bottom_dock] { - // dock.update(cx, |dock, cx| { - // if Some(dock.position()) != dock_to_reveal { - // if let Some(panel) = dock.active_panel() { - // if panel.is_zoomed(cx) { - // focus_center |= panel.has_focus(cx); - // dock.set_open(false, cx); - // } - // } - // } - // }); - // } + // If another dock is zoomed, hide it. + let mut focus_center = false; + for dock in [&self.left_dock, &self.right_dock, &self.bottom_dock] { + dock.update(cx, |dock, cx| { + if Some(dock.position()) != dock_to_reveal { + if let Some(panel) = dock.active_panel() { + if panel.is_zoomed(cx) { + focus_center |= panel.has_focus(cx); + dock.set_open(false, cx); + } + } + } + }); + } - // if focus_center { - // cx.focus_self(); - // } + if focus_center { + cx.focus(&self.focus_handle); + } - // if self.zoomed_position != dock_to_reveal { - // self.zoomed = None; - // self.zoomed_position = None; - // } + if self.zoomed_position != dock_to_reveal { + self.zoomed = None; + self.zoomed_position = None; + } - // cx.notify(); - // } + cx.notify(); + } fn add_pane(&mut self, _cx: &mut ViewContext) -> View { todo!() @@ -2288,214 +2290,213 @@ impl Workspace { // self.center.pane_at_pixel_position(target) // } - // fn handle_pane_focused(&mut self, pane: View, cx: &mut ViewContext) { - // if self.active_pane != pane { - // self.active_pane = pane.clone(); - // self.status_bar.update(cx, |status_bar, cx| { - // status_bar.set_active_pane(&self.active_pane, cx); - // }); - // self.active_item_path_changed(cx); - // self.last_active_center_pane = Some(pane.downgrade()); - // } + fn handle_pane_focused(&mut self, pane: View, cx: &mut ViewContext) { + if self.active_pane != pane { + self.active_pane = pane.clone(); + self.status_bar.update(cx, |status_bar, cx| { + status_bar.set_active_pane(&self.active_pane, cx); + }); + self.active_item_path_changed(cx); + self.last_active_center_pane = Some(pane.downgrade()); + } - // self.dismiss_zoomed_items_to_reveal(None, cx); - // if pane.read(cx).is_zoomed() { - // self.zoomed = Some(pane.downgrade().into_any()); - // } else { - // self.zoomed = None; - // } - // self.zoomed_position = None; - // self.update_active_view_for_followers(cx); + self.dismiss_zoomed_items_to_reveal(None, cx); + if pane.read(cx).is_zoomed() { + self.zoomed = Some(pane.downgrade().into()); + } else { + self.zoomed = None; + } + self.zoomed_position = None; + self.update_active_view_for_followers(cx); - // cx.notify(); - // } + cx.notify(); + } fn handle_pane_event( &mut self, - _pane: View, - _event: &pane::Event, - _cx: &mut ViewContext, + pane: View, + event: &pane::Event, + cx: &mut ViewContext, ) { - todo!() - // match event { - // pane::Event::AddItem { item } => item.added_to_pane(self, pane, cx), - // pane::Event::Split(direction) => { - // self.split_and_clone(pane, *direction, cx); - // } - // pane::Event::Remove => self.remove_pane(pane, cx), - // pane::Event::ActivateItem { local } => { - // if *local { - // self.unfollow(&pane, cx); - // } - // if &pane == self.active_pane() { - // self.active_item_path_changed(cx); - // } - // } - // pane::Event::ChangeItemTitle => { - // if pane == self.active_pane { - // self.active_item_path_changed(cx); - // } - // self.update_window_edited(cx); - // } - // pane::Event::RemoveItem { item_id } => { - // self.update_window_edited(cx); - // if let hash_map::Entry::Occupied(entry) = self.panes_by_item.entry(*item_id) { - // if entry.get().id() == pane.id() { - // entry.remove(); - // } - // } - // } - // pane::Event::Focus => { - // self.handle_pane_focused(pane.clone(), cx); - // } - // pane::Event::ZoomIn => { - // if pane == self.active_pane { - // pane.update(cx, |pane, cx| pane.set_zoomed(true, cx)); - // if pane.read(cx).has_focus() { - // self.zoomed = Some(pane.downgrade().into_any()); - // self.zoomed_position = None; - // } - // cx.notify(); - // } - // } - // pane::Event::ZoomOut => { - // pane.update(cx, |pane, cx| pane.set_zoomed(false, cx)); - // if self.zoomed_position.is_none() { - // self.zoomed = None; - // } - // cx.notify(); - // } - // } + match event { + pane::Event::AddItem { item } => item.added_to_pane(self, pane, cx), + pane::Event::Split(direction) => { + self.split_and_clone(pane, *direction, cx); + } + pane::Event::Remove => self.remove_pane(pane, cx), + pane::Event::ActivateItem { local } => { + if *local { + self.unfollow(&pane, cx); + } + if &pane == self.active_pane() { + self.active_item_path_changed(cx); + } + } + pane::Event::ChangeItemTitle => { + if pane == self.active_pane { + self.active_item_path_changed(cx); + } + self.update_window_edited(cx); + } + pane::Event::RemoveItem { item_id } => { + self.update_window_edited(cx); + if let hash_map::Entry::Occupied(entry) = self.panes_by_item.entry(*item_id) { + if entry.get().entity_id() == pane.entity_id() { + entry.remove(); + } + } + } + pane::Event::Focus => { + self.handle_pane_focused(pane.clone(), cx); + } + pane::Event::ZoomIn => { + if pane == self.active_pane { + pane.update(cx, |pane, cx| pane.set_zoomed(true, cx)); + if pane.read(cx).has_focus(cx) { + self.zoomed = Some(pane.downgrade().into()); + self.zoomed_position = None; + } + cx.notify(); + } + } + pane::Event::ZoomOut => { + pane.update(cx, |pane, cx| pane.set_zoomed(false, cx)); + if self.zoomed_position.is_none() { + self.zoomed = None; + } + cx.notify(); + } + } - // self.serialize_workspace(cx); + self.serialize_workspace(cx); } - // pub fn split_pane( - // &mut self, - // pane_to_split: View, - // split_direction: SplitDirection, - // cx: &mut ViewContext, - // ) -> View { - // let new_pane = self.add_pane(cx); - // self.center - // .split(&pane_to_split, &new_pane, split_direction) - // .unwrap(); - // cx.notify(); - // new_pane - // } + pub fn split_pane( + &mut self, + pane_to_split: View, + split_direction: SplitDirection, + cx: &mut ViewContext, + ) -> View { + let new_pane = self.add_pane(cx); + self.center + .split(&pane_to_split, &new_pane, split_direction) + .unwrap(); + cx.notify(); + new_pane + } - // pub fn split_and_clone( - // &mut self, - // pane: View, - // direction: SplitDirection, - // cx: &mut ViewContext, - // ) -> Option> { - // let item = pane.read(cx).active_item()?; - // let maybe_pane_handle = if let Some(clone) = item.clone_on_split(self.database_id(), cx) { - // let new_pane = self.add_pane(cx); - // new_pane.update(cx, |pane, cx| pane.add_item(clone, true, true, None, cx)); - // self.center.split(&pane, &new_pane, direction).unwrap(); - // Some(new_pane) - // } else { - // None - // }; - // cx.notify(); - // maybe_pane_handle - // } + pub fn split_and_clone( + &mut self, + pane: View, + direction: SplitDirection, + cx: &mut ViewContext, + ) -> Option> { + let item = pane.read(cx).active_item()?; + let maybe_pane_handle = if let Some(clone) = item.clone_on_split(self.database_id(), cx) { + let new_pane = self.add_pane(cx); + new_pane.update(cx, |pane, cx| pane.add_item(clone, true, true, None, cx)); + self.center.split(&pane, &new_pane, direction).unwrap(); + Some(new_pane) + } else { + None + }; + cx.notify(); + maybe_pane_handle + } - // pub fn split_pane_with_item( - // &mut self, - // pane_to_split: WeakView, - // split_direction: SplitDirection, - // from: WeakView, - // item_id_to_move: usize, - // cx: &mut ViewContext, - // ) { - // let Some(pane_to_split) = pane_to_split.upgrade(cx) else { - // return; - // }; - // let Some(from) = from.upgrade(cx) else { - // return; - // }; + pub fn split_pane_with_item( + &mut self, + pane_to_split: WeakView, + split_direction: SplitDirection, + from: WeakView, + item_id_to_move: EntityId, + cx: &mut ViewContext, + ) { + let Some(pane_to_split) = pane_to_split.upgrade() else { + return; + }; + let Some(from) = from.upgrade() else { + return; + }; - // let new_pane = self.add_pane(cx); - // self.move_item(from.clone(), new_pane.clone(), item_id_to_move, 0, cx); - // self.center - // .split(&pane_to_split, &new_pane, split_direction) - // .unwrap(); - // cx.notify(); - // } + let new_pane = self.add_pane(cx); + self.move_item(from.clone(), new_pane.clone(), item_id_to_move, 0, cx); + self.center + .split(&pane_to_split, &new_pane, split_direction) + .unwrap(); + cx.notify(); + } - // pub fn split_pane_with_project_entry( - // &mut self, - // pane_to_split: WeakView, - // split_direction: SplitDirection, - // project_entry: ProjectEntryId, - // cx: &mut ViewContext, - // ) -> Option>> { - // let pane_to_split = pane_to_split.upgrade(cx)?; - // let new_pane = self.add_pane(cx); - // self.center - // .split(&pane_to_split, &new_pane, split_direction) - // .unwrap(); + pub fn split_pane_with_project_entry( + &mut self, + pane_to_split: WeakView, + split_direction: SplitDirection, + project_entry: ProjectEntryId, + cx: &mut ViewContext, + ) -> Option>> { + let pane_to_split = pane_to_split.upgrade()?; + let new_pane = self.add_pane(cx); + self.center + .split(&pane_to_split, &new_pane, split_direction) + .unwrap(); - // let path = self.project.read(cx).path_for_entry(project_entry, cx)?; - // let task = self.open_path(path, Some(new_pane.downgrade()), true, cx); - // Some(cx.foreground().spawn(async move { - // task.await?; - // Ok(()) - // })) - // } + let path = self.project.read(cx).path_for_entry(project_entry, cx)?; + let task = self.open_path(path, Some(new_pane.downgrade()), true, cx); + Some(cx.foreground_executor().spawn(async move { + task.await?; + Ok(()) + })) + } - // pub fn move_item( - // &mut self, - // source: View, - // destination: View, - // item_id_to_move: usize, - // destination_index: usize, - // cx: &mut ViewContext, - // ) { - // let item_to_move = source - // .read(cx) - // .items() - // .enumerate() - // .find(|(_, item_handle)| item_handle.id() == item_id_to_move); + pub fn move_item( + &mut self, + source: View, + destination: View, + item_id_to_move: EntityId, + destination_index: usize, + cx: &mut ViewContext, + ) { + let item_to_move = source + .read(cx) + .items() + .enumerate() + .find(|(_, item_handle)| item_handle.id() == item_id_to_move); - // if item_to_move.is_none() { - // log::warn!("Tried to move item handle which was not in `from` pane. Maybe tab was closed during drop"); - // return; - // } - // let (item_ix, item_handle) = item_to_move.unwrap(); - // let item_handle = item_handle.clone(); + if item_to_move.is_none() { + log::warn!("Tried to move item handle which was not in `from` pane. Maybe tab was closed during drop"); + return; + } + let (item_ix, item_handle) = item_to_move.unwrap(); + let item_handle = item_handle.clone(); - // if source != destination { - // // Close item from previous pane - // source.update(cx, |source, cx| { - // source.remove_item(item_ix, false, cx); - // }); - // } + if source != destination { + // Close item from previous pane + source.update(cx, |source, cx| { + source.remove_item(item_ix, false, cx); + }); + } - // // This automatically removes duplicate items in the pane - // destination.update(cx, |destination, cx| { - // destination.add_item(item_handle, true, true, Some(destination_index), cx); - // cx.focus_self(); - // }); - // } + // This automatically removes duplicate items in the pane + destination.update(cx, |destination, cx| { + destination.add_item(item_handle, true, true, Some(destination_index), cx); + destination.focus(cx) + }); + } - // fn remove_pane(&mut self, pane: View, cx: &mut ViewContext) { - // if self.center.remove(&pane).unwrap() { - // self.force_remove_pane(&pane, cx); - // self.unfollow(&pane, cx); - // self.last_leaders_by_pane.remove(&pane.downgrade()); - // for removed_item in pane.read(cx).items() { - // self.panes_by_item.remove(&removed_item.id()); - // } + fn remove_pane(&mut self, pane: View, cx: &mut ViewContext) { + if self.center.remove(&pane).unwrap() { + self.force_remove_pane(&pane, cx); + self.unfollow(&pane, cx); + self.last_leaders_by_pane.remove(&pane.downgrade()); + for removed_item in pane.read(cx).items() { + self.panes_by_item.remove(&removed_item.id()); + } - // cx.notify(); - // } else { - // self.active_item_path_changed(cx); - // } - // } + cx.notify(); + } else { + self.active_item_path_changed(cx); + } + } pub fn panes(&self) -> &[View] { &self.panes @@ -2708,12 +2709,12 @@ impl Workspace { .child("Collab title bar Item") // self.titlebar_item } - // fn active_item_path_changed(&mut self, cx: &mut ViewContext) { - // let active_entry = self.active_project_path(cx); - // self.project - // .update(cx, |project, cx| project.set_active_path(active_entry, cx)); - // self.update_window_title(cx); - // } + fn active_item_path_changed(&mut self, cx: &mut ViewContext) { + let active_entry = self.active_project_path(cx); + self.project + .update(cx, |project, cx| project.set_active_path(active_entry, cx)); + self.update_window_title(cx); + } fn update_window_title(&mut self, cx: &mut ViewContext) { let project = self.project().read(cx); @@ -3010,7 +3011,7 @@ impl Workspace { fn update_active_view_for_followers(&mut self, cx: &mut ViewContext) { let mut is_project_item = true; let mut update = proto::UpdateActiveView::default(); - if self.active_pane.read(cx).has_focus() { + if self.active_pane.read(cx).has_focus(cx) { let item = self .active_item(cx) .and_then(|item| item.to_followable_item_handle(cx)); @@ -3105,7 +3106,7 @@ impl Workspace { } for (pane, item) in items_to_activate { - let pane_was_focused = pane.read(cx).has_focus(); + let pane_was_focused = pane.read(cx).has_focus(cx); if let Some(index) = pane.update(cx, |pane, _| pane.index_for_item(item.as_ref())) { pane.update(cx, |pane, cx| pane.activate_item(index, false, false, cx)); } else { @@ -3242,7 +3243,7 @@ impl Workspace { // } fn serialize_workspace(&self, cx: &mut ViewContext) { - fn serialize_pane_handle(pane_handle: &View, cx: &AppContext) -> SerializedPane { + fn serialize_pane_handle(pane_handle: &View, cx: &WindowContext) -> SerializedPane { let (items, active) = { let pane = pane_handle.read(cx); let active_item_id = pane.active_item().map(|item| item.id()); @@ -3256,7 +3257,7 @@ impl Workspace { }) }) .collect::>(), - pane.has_focus(), + pane.has_focus(cx), ) }; @@ -3265,7 +3266,7 @@ impl Workspace { fn build_serialized_pane_group( pane_group: &Member, - cx: &AppContext, + cx: &WindowContext, ) -> SerializedPaneGroup { match pane_group { Member::Axis(PaneAxis {