From db3119b5537c5f16b0165292f3b3f8dfd43ae79f Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 12 Dec 2022 12:25:52 -0800 Subject: [PATCH 1/5] Add check for if the user wants a blanks workspace when deserializing --- crates/workspace/src/persistence.rs | 9 +++++++++ crates/workspace/src/workspace.rs | 17 ++++++++++------- crates/zed/src/zed.rs | 2 +- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 2d4ae919f95d4fcaeb8f0a7466e39098132e1003..918e37fba96942dd4aa751b03e92390c890b4511 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -371,6 +371,15 @@ impl WorkspaceDb { Ok(()) } + + query!{ + fn update_timestamp(workspace_id: WorkspaceId) -> Result<()> { + UPDATE workspaces + SET timestamp = CURRENT_TIMESTAMP + WHERE workspace_id = ? + } + } + } #[cfg(test)] diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 7dc8ddab067e46de209cb5ad7b1a480775a14369..43face78d8320d916c4b71e7b7f6a6e302a48978 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -172,7 +172,7 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { let app_state = Arc::downgrade(&app_state); move |_: &NewFile, cx: &mut MutableAppContext| { if let Some(app_state) = app_state.upgrade() { - open_new(&app_state, cx).detach(); + open_new(&app_state, false, cx).detach(); } } }); @@ -180,7 +180,7 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { let app_state = Arc::downgrade(&app_state); move |_: &NewWindow, cx: &mut MutableAppContext| { if let Some(app_state) = app_state.upgrade() { - open_new(&app_state, cx).detach(); + open_new(&app_state, true, cx).detach(); } } }); @@ -652,6 +652,7 @@ impl Workspace { fn new_local( abs_paths: Vec, app_state: Arc, + blank: bool, cx: &mut MutableAppContext, ) -> Task<( ViewHandle, @@ -666,7 +667,9 @@ impl Workspace { ); cx.spawn(|mut cx| async move { - let serialized_workspace = persistence::DB.workspace_for_roots(&abs_paths.as_slice()); + let serialized_workspace = (!blank) + .then(|| persistence::DB.workspace_for_roots(&abs_paths.as_slice())) + .flatten(); let paths_to_open = serialized_workspace .as_ref() @@ -804,7 +807,7 @@ impl Workspace { if self.project.read(cx).is_local() { Task::Ready(Some(callback(self, cx))) } else { - let task = Self::new_local(Vec::new(), app_state.clone(), cx); + let task = Self::new_local(Vec::new(), app_state.clone(), true, cx); cx.spawn(|_vh, mut cx| async move { let (workspace, _) = task.await; workspace.update(&mut cx, callback) @@ -2652,7 +2655,7 @@ pub fn open_paths( .contains(&false); cx.update(|cx| { - let task = Workspace::new_local(abs_paths, app_state.clone(), cx); + let task = Workspace::new_local(abs_paths, app_state.clone(), false, cx); cx.spawn(|mut cx| async move { let (workspace, items) = task.await; @@ -2671,8 +2674,8 @@ pub fn open_paths( }) } -pub fn open_new(app_state: &Arc, cx: &mut MutableAppContext) -> Task<()> { - let task = Workspace::new_local(Vec::new(), app_state.clone(), cx); +pub fn open_new(app_state: &Arc, blank: bool, cx: &mut MutableAppContext) -> Task<()> { + let task = Workspace::new_local(Vec::new(), app_state.clone(), blank, cx); cx.spawn(|mut cx| async move { let (workspace, opened_paths) = task.await; diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 9a827da8b7c3f7aef969c8562a42de0fae97aa2a..67ac4e8f2bdda7b583e7967522b0e0ea06bc7635 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -765,7 +765,7 @@ mod tests { #[gpui::test] async fn test_new_empty_workspace(cx: &mut TestAppContext) { let app_state = init(cx); - cx.update(|cx| open_new(&app_state, cx)).await; + cx.update(|cx| open_new(&app_state, true, cx)).await; let window_id = *cx.window_ids().first().unwrap(); let workspace = cx.root_view::(window_id).unwrap(); From 5a29a74956a2d445fe168fdb016918cb98c30ef2 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 12 Dec 2022 13:29:02 -0800 Subject: [PATCH 2/5] Fetch last workspace explicitly when starting Zed co-authored-by: Max --- crates/drag_and_drop/src/drag_and_drop.rs | 4 +-- crates/workspace/src/persistence.rs | 40 +++++++++++++---------- crates/workspace/src/workspace.rs | 28 +++++++++------- crates/zed/src/main.rs | 14 ++++++-- crates/zed/src/zed.rs | 2 +- 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/crates/drag_and_drop/src/drag_and_drop.rs b/crates/drag_and_drop/src/drag_and_drop.rs index a34fa83a4c59a9d48b997beecf91ebbb4a7ea83b..b4881258f7f4ffbb863a79478ff73037a64b1459 100644 --- a/crates/drag_and_drop/src/drag_and_drop.rs +++ b/crates/drag_and_drop/src/drag_and_drop.rs @@ -139,9 +139,7 @@ impl DragAndDrop { region_offset, region, }) => { - if (dbg!(event.position) - (dbg!(region.origin() + region_offset))).length() - > DEAD_ZONE - { + if (event.position - (region.origin() + region_offset)).length() > DEAD_ZONE { this.currently_dragged = Some(State::Dragging { window_id, region_offset, diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 918e37fba96942dd4aa751b03e92390c890b4511..39a488324766ca881f64fa96753261a4962dcab6 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -8,7 +8,7 @@ use anyhow::{anyhow, bail, Context, Result}; use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql}; use gpui::Axis; -use util::{iife, unzip_option, ResultExt}; +use util::{ unzip_option, ResultExt}; use crate::dock::DockPosition; use crate::WorkspaceId; @@ -96,22 +96,16 @@ impl WorkspaceDb { WorkspaceLocation, bool, DockPosition, - ) = iife!({ - if worktree_roots.len() == 0 { - self.select_row(sql!( - SELECT workspace_id, workspace_location, left_sidebar_open, dock_visible, dock_anchor - FROM workspaces - ORDER BY timestamp DESC LIMIT 1))?()? - } else { - self.select_row_bound(sql!( - SELECT workspace_id, workspace_location, left_sidebar_open, dock_visible, dock_anchor - FROM workspaces - WHERE workspace_location = ?))?(&workspace_location)? - } + ) = + self.select_row_bound(sql!{ + SELECT workspace_id, workspace_location, left_sidebar_open, dock_visible, dock_anchor + FROM workspaces + WHERE workspace_location = ? + }) + .and_then(|mut prepared_statement| (prepared_statement)(&workspace_location)) .context("No workspaces found") - }) - .warn_on_err() - .flatten()?; + .warn_on_err() + .flatten()?; Some(SerializedWorkspace { id: workspace_id, @@ -205,6 +199,16 @@ impl WorkspaceDb { } } + query! { + pub fn last_workspace() -> Result> { + SELECT workspace_location + FROM workspaces + WHERE workspace_location IS NOT NULL + ORDER BY timestamp DESC + LIMIT 1 + } + } + fn get_center_pane_group(&self, workspace_id: WorkspaceId) -> Result { self.get_pane_group(workspace_id, None)? .into_iter() @@ -371,9 +375,9 @@ impl WorkspaceDb { Ok(()) } - + query!{ - fn update_timestamp(workspace_id: WorkspaceId) -> Result<()> { + pub async fn update_timestamp(workspace_id: WorkspaceId) -> Result<()> { UPDATE workspaces SET timestamp = CURRENT_TIMESTAMP WHERE workspace_id = ? diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 43face78d8320d916c4b71e7b7f6a6e302a48978..18cda0701ddeacbb3be6427b317f9d641ebca703 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -172,15 +172,16 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { let app_state = Arc::downgrade(&app_state); move |_: &NewFile, cx: &mut MutableAppContext| { if let Some(app_state) = app_state.upgrade() { - open_new(&app_state, false, cx).detach(); + open_new(&app_state, cx).detach(); } } }); + cx.add_global_action({ let app_state = Arc::downgrade(&app_state); move |_: &NewWindow, cx: &mut MutableAppContext| { if let Some(app_state) = app_state.upgrade() { - open_new(&app_state, true, cx).detach(); + open_new(&app_state, cx).detach(); } } }); @@ -652,7 +653,6 @@ impl Workspace { fn new_local( abs_paths: Vec, app_state: Arc, - blank: bool, cx: &mut MutableAppContext, ) -> Task<( ViewHandle, @@ -667,9 +667,7 @@ impl Workspace { ); cx.spawn(|mut cx| async move { - let serialized_workspace = (!blank) - .then(|| persistence::DB.workspace_for_roots(&abs_paths.as_slice())) - .flatten(); + let serialized_workspace = persistence::DB.workspace_for_roots(&abs_paths.as_slice()); let paths_to_open = serialized_workspace .as_ref() @@ -807,7 +805,7 @@ impl Workspace { if self.project.read(cx).is_local() { Task::Ready(Some(callback(self, cx))) } else { - let task = Self::new_local(Vec::new(), app_state.clone(), true, cx); + let task = Self::new_local(Vec::new(), app_state.clone(), cx); cx.spawn(|_vh, mut cx| async move { let (workspace, _) = task.await; workspace.update(&mut cx, callback) @@ -2184,7 +2182,11 @@ impl Workspace { } pub fn on_window_activation_changed(&mut self, active: bool, cx: &mut ViewContext) { - if !active { + if active { + cx.background() + .spawn(persistence::DB.update_timestamp(self.database_id())) + .detach(); + } else { for pane in &self.panes { pane.update(cx, |pane, cx| { if let Some(item) = pane.active_item() { @@ -2621,6 +2623,10 @@ pub fn activate_workspace_for_project( None } +pub fn last_opened_workspace_paths() -> Option { + DB.last_workspace().log_err().flatten() +} + #[allow(clippy::type_complexity)] pub fn open_paths( abs_paths: &[PathBuf], @@ -2655,7 +2661,7 @@ pub fn open_paths( .contains(&false); cx.update(|cx| { - let task = Workspace::new_local(abs_paths, app_state.clone(), false, cx); + let task = Workspace::new_local(abs_paths, app_state.clone(), cx); cx.spawn(|mut cx| async move { let (workspace, items) = task.await; @@ -2674,8 +2680,8 @@ pub fn open_paths( }) } -pub fn open_new(app_state: &Arc, blank: bool, cx: &mut MutableAppContext) -> Task<()> { - let task = Workspace::new_local(Vec::new(), app_state.clone(), blank, cx); +pub fn open_new(app_state: &Arc, cx: &mut MutableAppContext) -> Task<()> { + let task = Workspace::new_local(Vec::new(), app_state.clone(), cx); cx.spawn(|mut cx| async move { let (workspace, opened_paths) = task.await; diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 09a20b566002158d6f9f4e3471fb9e39c8852a73..bffd567505b1973163f50ecc8afdd28886a48470 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -169,7 +169,7 @@ fn main() { cx.platform().activate(true); let paths = collect_path_args(); if paths.is_empty() { - cx.dispatch_global_action(NewFile); + restore_or_create_workspace(cx); } else { cx.dispatch_global_action(OpenPaths { paths }); } @@ -178,7 +178,7 @@ fn main() { cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx)) .detach(); } else { - cx.dispatch_global_action(NewFile); + restore_or_create_workspace(cx); } cx.spawn(|cx| async move { while let Some(connection) = cli_connections_rx.next().await { @@ -202,6 +202,16 @@ fn main() { }); } +fn restore_or_create_workspace(cx: &mut gpui::MutableAppContext) { + if let Some(location) = workspace::last_opened_workspace_paths() { + cx.dispatch_global_action(OpenPaths { + paths: location.paths().as_ref().clone(), + }) + } else { + cx.dispatch_global_action(NewFile); + } +} + fn init_paths() { std::fs::create_dir_all(&*util::paths::CONFIG_DIR).expect("could not create config path"); std::fs::create_dir_all(&*util::paths::LANGUAGES_DIR).expect("could not create languages path"); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 67ac4e8f2bdda7b583e7967522b0e0ea06bc7635..9a827da8b7c3f7aef969c8562a42de0fae97aa2a 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -765,7 +765,7 @@ mod tests { #[gpui::test] async fn test_new_empty_workspace(cx: &mut TestAppContext) { let app_state = init(cx); - cx.update(|cx| open_new(&app_state, true, cx)).await; + cx.update(|cx| open_new(&app_state, cx)).await; let window_id = *cx.window_ids().first().unwrap(); let workspace = cx.root_view::(window_id).unwrap(); From 9ef00ea44ccd81210dcdc29a1fca9d519d209f2a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 12 Dec 2022 15:36:30 -0800 Subject: [PATCH 3/5] Avoid breaking follow when syncing leader's scroll position Co-authored-by: Mikayla Maki Co-authored-by: Kay Simmons --- crates/editor/src/editor_tests.rs | 26 ++++++++++++++++++++++++++ crates/editor/src/items.rs | 5 ++--- crates/editor/src/scroll.rs | 8 ++++---- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 9a6cd23453dc94a596cc180afd6e6c3ff2c79b33..582c75904d383a4228aa58651ce2ed72fc2d46aa 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -4983,9 +4983,11 @@ fn test_following(cx: &mut gpui::MutableAppContext) { |cx| build_editor(buffer.clone(), cx), ); + let is_still_following = Rc::new(RefCell::new(true)); let pending_update = Rc::new(RefCell::new(None)); follower.update(cx, { let update = pending_update.clone(); + let is_still_following = is_still_following.clone(); |_, cx| { cx.subscribe(&leader, move |_, leader, event, cx| { leader @@ -4993,6 +4995,13 @@ fn test_following(cx: &mut gpui::MutableAppContext) { .add_event_to_update_proto(event, &mut *update.borrow_mut(), cx); }) .detach(); + + cx.subscribe(&follower, move |_, _, event, cx| { + if Editor::should_unfollow_on_event(event, cx) { + *is_still_following.borrow_mut() = false; + } + }) + .detach(); } }); @@ -5006,6 +5015,7 @@ fn test_following(cx: &mut gpui::MutableAppContext) { .unwrap(); }); assert_eq!(follower.read(cx).selections.ranges(cx), vec![1..1]); + assert_eq!(*is_still_following.borrow(), true); // Update the scroll position only leader.update(cx, |leader, cx| { @@ -5020,6 +5030,7 @@ fn test_following(cx: &mut gpui::MutableAppContext) { follower.update(cx, |follower, cx| follower.scroll_position(cx)), vec2f(1.5, 3.5) ); + assert_eq!(*is_still_following.borrow(), true); // Update the selections and scroll position leader.update(cx, |leader, cx| { @@ -5036,6 +5047,7 @@ fn test_following(cx: &mut gpui::MutableAppContext) { assert!(follower.scroll_manager.has_autoscroll_request()); }); assert_eq!(follower.read(cx).selections.ranges(cx), vec![0..0]); + assert_eq!(*is_still_following.borrow(), true); // Creating a pending selection that precedes another selection leader.update(cx, |leader, cx| { @@ -5048,6 +5060,7 @@ fn test_following(cx: &mut gpui::MutableAppContext) { .unwrap(); }); assert_eq!(follower.read(cx).selections.ranges(cx), vec![0..0, 1..1]); + assert_eq!(*is_still_following.borrow(), true); // Extend the pending selection so that it surrounds another selection leader.update(cx, |leader, cx| { @@ -5059,6 +5072,19 @@ fn test_following(cx: &mut gpui::MutableAppContext) { .unwrap(); }); assert_eq!(follower.read(cx).selections.ranges(cx), vec![0..2]); + + // Scrolling locally breaks the follow + follower.update(cx, |follower, cx| { + let top_anchor = follower.buffer().read(cx).read(cx).anchor_after(0); + follower.set_scroll_anchor( + ScrollAnchor { + top_anchor, + offset: vec2f(0.0, 0.5), + }, + cx, + ); + }); + assert_eq!(*is_still_following.borrow(), false); } #[test] diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 0efce57d5f2963c74256ebc20ac781b7cd004ddf..5883091d4794c3fd7be7dad4617b902e944d4bd6 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -88,7 +88,7 @@ impl FollowableItem for Editor { } if let Some(anchor) = state.scroll_top_anchor { - editor.set_scroll_anchor_internal( + editor.set_scroll_anchor_remote( ScrollAnchor { top_anchor: Anchor { buffer_id: Some(state.buffer_id as usize), @@ -98,7 +98,6 @@ impl FollowableItem for Editor { }, offset: vec2f(state.scroll_x, state.scroll_y), }, - false, cx, ); } @@ -213,7 +212,7 @@ impl FollowableItem for Editor { self.set_selections_from_remote(selections, cx); self.request_autoscroll_remotely(Autoscroll::newest(), cx); } else if let Some(anchor) = message.scroll_top_anchor { - self.set_scroll_anchor( + self.set_scroll_anchor_remote( ScrollAnchor { top_anchor: Anchor { buffer_id: Some(buffer_id), diff --git a/crates/editor/src/scroll.rs b/crates/editor/src/scroll.rs index 5cb58e21e990bdcc3923a9603207d35eeb431838..eb89bfeec206d44af2a60602919309c353f3c7e1 100644 --- a/crates/editor/src/scroll.rs +++ b/crates/editor/src/scroll.rs @@ -284,17 +284,17 @@ impl Editor { } pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext) { - self.set_scroll_anchor_internal(scroll_anchor, true, cx); + hide_hover(self, cx); + self.scroll_manager.set_anchor(scroll_anchor, true, cx); } - pub(crate) fn set_scroll_anchor_internal( + pub(crate) fn set_scroll_anchor_remote( &mut self, scroll_anchor: ScrollAnchor, - local: bool, cx: &mut ViewContext, ) { hide_hover(self, cx); - self.scroll_manager.set_anchor(scroll_anchor, local, cx); + self.scroll_manager.set_anchor(scroll_anchor, false, cx); } pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext) { From cd2d593a6c6a2b8ceff4c2d260094e31633c991d Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 12 Dec 2022 15:29:36 -0800 Subject: [PATCH 4/5] Fixed issue where the NextScreen action would never have an effect --- crates/editor/src/editor.rs | 1 - crates/editor/src/scroll/actions.rs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index ad21622fd9eb6d52f59a26dc85e3881165a44eef..ab2bdf1889a7ab04bedf2a95702dad73b3394681 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -184,7 +184,6 @@ actions!( Paste, Undo, Redo, - NextScreen, MoveUp, PageUp, MoveDown, diff --git a/crates/editor/src/scroll/actions.rs b/crates/editor/src/scroll/actions.rs index 8e574025326c3b2abb28245cc473a294198926ea..fb3dec01291e40024b7882c0d00628aab9cb20e4 100644 --- a/crates/editor/src/scroll/actions.rs +++ b/crates/editor/src/scroll/actions.rs @@ -64,15 +64,15 @@ impl Editor { return None; } - self.context_menu.as_mut()?; + if self.mouse_context_menu.read(cx).visible() { + return None; + } if matches!(self.mode, EditorMode::SingleLine) { cx.propagate_action(); return None; } - self.request_autoscroll(Autoscroll::Next, cx); - Some(()) } From 9bf0a02eae0baeb246ac845a8b7c39fbb32668d0 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 12 Dec 2022 17:41:15 -0800 Subject: [PATCH 5/5] Allow an empty center group to successfully deserialize into an empty pane. Fix error when deserializing pane axis which caused it's members.len() > 1 invariant to be violated Fix failure to gain center pane focus when failing to deserialize a center pane entirely Co-authored-by: Max --- crates/workspace/src/persistence.rs | 6 +++--- crates/workspace/src/persistence/model.rs | 8 ++++++-- crates/workspace/src/workspace.rs | 23 +++++++++++++++++------ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 39a488324766ca881f64fa96753261a4962dcab6..9f957f6e18ba145bb8e16ebba15c2743d3197d92 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -210,10 +210,10 @@ impl WorkspaceDb { } fn get_center_pane_group(&self, workspace_id: WorkspaceId) -> Result { - self.get_pane_group(workspace_id, None)? + Ok(self.get_pane_group(workspace_id, None)? .into_iter() .next() - .context("No center pane group") + .unwrap_or_else(|| SerializedPaneGroup::Pane(SerializedPane { active: true, children: vec![] }))) } fn get_pane_group( @@ -267,7 +267,7 @@ impl WorkspaceDb { // Filter out panes and pane groups which don't have any children or items .filter(|pane_group| match pane_group { Ok(SerializedPaneGroup::Group { children, .. }) => !children.is_empty(), - Ok(SerializedPaneGroup::Pane(pane)) => !pane.children.is_empty(), + Ok(SerializedPaneGroup::Pane(pane)) => !pane.children.is_empty(), _ => true, }) .collect::>() diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index c75488561f50735ae98c0c4e08a256995a9cba55..b264114fb68820203f90cd8b139d2d85a4836864 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -106,7 +106,6 @@ impl SerializedPaneGroup { .await { members.push(new_member); - current_active_pane = current_active_pane.or(active_pane); } } @@ -115,6 +114,10 @@ impl SerializedPaneGroup { return None; } + if members.len() == 1 { + return Some((members.remove(0), current_active_pane)); + } + Some(( Member::Axis(PaneAxis { axis: *axis, @@ -130,9 +133,10 @@ impl SerializedPaneGroup { .deserialize_to(project, &pane, workspace_id, workspace, cx) .await; - if pane.read_with(cx, |pane, _| pane.items().next().is_some()) { + if pane.read_with(cx, |pane, _| pane.items_len() != 0) { Some((Member::Pane(pane.clone()), active.then(|| pane))) } else { + workspace.update(cx, |workspace, cx| workspace.remove_pane(pane, cx)); None } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 18cda0701ddeacbb3be6427b317f9d641ebca703..387a18006a0d703c8c04cd55201156c975854921 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2300,6 +2300,9 @@ impl Workspace { } if let Some(location) = self.location(cx) { + // Load bearing special case: + // - with_local_workspace() relies on this to not have other stuff open + // when you open your log if !location.paths().is_empty() { let dock_pane = serialize_pane_handle(self.dock.pane(), cx); let center_group = build_serialized_pane_group(&self.center.root, cx); @@ -2327,9 +2330,14 @@ impl Workspace { ) { cx.spawn(|mut cx| async move { if let Some(workspace) = workspace.upgrade(&cx) { - let (project, dock_pane_handle) = workspace.read_with(&cx, |workspace, _| { - (workspace.project().clone(), workspace.dock_pane().clone()) - }); + let (project, dock_pane_handle, old_center_pane) = + workspace.read_with(&cx, |workspace, _| { + ( + workspace.project().clone(), + workspace.dock_pane().clone(), + workspace.last_active_center_pane.clone(), + ) + }); serialized_workspace .dock_pane @@ -2365,11 +2373,14 @@ impl Workspace { cx.focus(workspace.panes.last().unwrap().clone()); } } else { - cx.focus_self(); + let old_center_handle = old_center_pane.and_then(|weak| weak.upgrade(cx)); + if let Some(old_center_handle) = old_center_handle { + cx.focus(old_center_handle) + } else { + cx.focus_self() + } } - // Note, if this is moved after 'set_dock_position' - // it causes an infinite loop. if workspace.left_sidebar().read(cx).is_open() != serialized_workspace.left_sidebar_open {