Reactivate the correct item in each pane when deserializing

Kay Simmons created

Change summary

crates/db/src/db.rs                            |  4 
crates/terminal/src/terminal_container_view.rs |  1 
crates/workspace/src/persistence.rs            | 67 ++++++++++---------
crates/workspace/src/persistence/model.rs      | 31 ++++++++-
crates/workspace/src/workspace.rs              | 40 ++++++-----
5 files changed, 84 insertions(+), 59 deletions(-)

Detailed changes

crates/db/src/db.rs 🔗

@@ -113,7 +113,6 @@ macro_rules! query {
         $vis async fn $id(&self) -> $crate::anyhow::Result<()> {
             use $crate::anyhow::Context;
 
-
             self.write(|connection| {
                 let sql_stmt = $crate::sqlez_macros::sql!($($sql)+);
 
@@ -143,7 +142,6 @@ macro_rules! query {
         $vis async fn $id(&self, $arg: $arg_type) -> $crate::anyhow::Result<()> {
             use $crate::anyhow::Context;
 
-
             self.write(move |connection| {
                 let sql_stmt = $crate::sqlez_macros::sql!($($sql)+);
 
@@ -186,7 +184,7 @@ macro_rules! query {
                  ))
          }
     };
-    ($vis:vis async fn $id:ident() ->  Result<Vec<$return_type:ty>> { $($sql:tt)+ }) => {
+    ($vis:vis async fn $id:ident() -> Result<Vec<$return_type:ty>> { $($sql:tt)+ }) => {
         pub async fn $id(&self) -> $crate::anyhow::Result<Vec<$return_type>> {
             use $crate::anyhow::Context;
 

crates/workspace/src/persistence.rs 🔗

@@ -76,6 +76,7 @@ impl Domain for Workspace {
                 pane_id INTEGER NOT NULL,
                 kind TEXT NOT NULL,
                 position INTEGER NOT NULL,
+                active INTEGER NOT NULL,
                 FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id)
                     ON DELETE CASCADE
                     ON UPDATE CASCADE,
@@ -352,7 +353,7 @@ impl WorkspaceDb {
 
     fn get_items(&self, pane_id: PaneId) -> Result<Vec<SerializedItem>> {
         Ok(self.select_bound(sql!(
-            SELECT kind, item_id FROM items
+            SELECT kind, item_id, active FROM items
             WHERE pane_id = ?
             ORDER BY position
         ))?(pane_id)?)
@@ -365,10 +366,9 @@ impl WorkspaceDb {
         items: &[SerializedItem],
     ) -> Result<()> {
         let mut insert = conn.exec_bound(sql!(
-            INSERT INTO items(workspace_id, pane_id, position, kind, item_id) VALUES (?, ?, ?, ?, ?)
+            INSERT INTO items(workspace_id, pane_id, position, kind, item_id, active) VALUES (?, ?, ?, ?, ?, ?)
         )).context("Preparing insertion")?;
         for (position, item) in items.iter().enumerate() {
-            dbg!(item);
             insert((workspace_id, pane_id, position, item))?;
         }
 
@@ -497,6 +497,7 @@ mod tests {
         workspace_2.dock_pane.children.push(SerializedItem {
             kind: Arc::from("Test"),
             item_id: 10,
+            active: true,
         });
         db.save_workspace(workspace_2).await;
 
@@ -523,10 +524,10 @@ mod tests {
 
         let dock_pane = crate::persistence::model::SerializedPane {
             children: vec![
-                SerializedItem::new("Terminal", 1),
-                SerializedItem::new("Terminal", 2),
-                SerializedItem::new("Terminal", 3),
-                SerializedItem::new("Terminal", 4),
+                SerializedItem::new("Terminal", 1, false),
+                SerializedItem::new("Terminal", 2, false),
+                SerializedItem::new("Terminal", 3, true),
+                SerializedItem::new("Terminal", 4, false),
             ],
             active: false,
         };
@@ -544,15 +545,15 @@ mod tests {
                     children: vec![
                         SerializedPaneGroup::Pane(SerializedPane::new(
                             vec![
-                                SerializedItem::new("Terminal", 5),
-                                SerializedItem::new("Terminal", 6),
+                                SerializedItem::new("Terminal", 5, false),
+                                SerializedItem::new("Terminal", 6, true),
                             ],
                             false,
                         )),
                         SerializedPaneGroup::Pane(SerializedPane::new(
                             vec![
-                                SerializedItem::new("Terminal", 7),
-                                SerializedItem::new("Terminal", 8),
+                                SerializedItem::new("Terminal", 7, true),
+                                SerializedItem::new("Terminal", 8, false),
                             ],
                             false,
                         )),
@@ -560,8 +561,8 @@ mod tests {
                 },
                 SerializedPaneGroup::Pane(SerializedPane::new(
                     vec![
-                        SerializedItem::new("Terminal", 9),
-                        SerializedItem::new("Terminal", 10),
+                        SerializedItem::new("Terminal", 9, false),
+                        SerializedItem::new("Terminal", 10, true),
                     ],
                     false,
                 )),
@@ -689,10 +690,10 @@ mod tests {
 
         let dock_pane = crate::persistence::model::SerializedPane::new(
             vec![
-                SerializedItem::new("Terminal", 1),
-                SerializedItem::new("Terminal", 4),
-                SerializedItem::new("Terminal", 2),
-                SerializedItem::new("Terminal", 3),
+                SerializedItem::new("Terminal", 1, false),
+                SerializedItem::new("Terminal", 4, false),
+                SerializedItem::new("Terminal", 2, false),
+                SerializedItem::new("Terminal", 3, true),
             ],
             false,
         );
@@ -725,15 +726,15 @@ mod tests {
                     children: vec![
                         SerializedPaneGroup::Pane(SerializedPane::new(
                             vec![
-                                SerializedItem::new("Terminal", 1),
-                                SerializedItem::new("Terminal", 2),
+                                SerializedItem::new("Terminal", 1, false),
+                                SerializedItem::new("Terminal", 2, true),
                             ],
                             false,
                         )),
                         SerializedPaneGroup::Pane(SerializedPane::new(
                             vec![
-                                SerializedItem::new("Terminal", 4),
-                                SerializedItem::new("Terminal", 3),
+                                SerializedItem::new("Terminal", 4, false),
+                                SerializedItem::new("Terminal", 3, true),
                             ],
                             true,
                         )),
@@ -741,8 +742,8 @@ mod tests {
                 },
                 SerializedPaneGroup::Pane(SerializedPane::new(
                     vec![
-                        SerializedItem::new("Terminal", 5),
-                        SerializedItem::new("Terminal", 6),
+                        SerializedItem::new("Terminal", 5, true),
+                        SerializedItem::new("Terminal", 6, false),
                     ],
                     false,
                 )),
@@ -772,15 +773,15 @@ mod tests {
                     children: vec![
                         SerializedPaneGroup::Pane(SerializedPane::new(
                             vec![
-                                SerializedItem::new("Terminal", 1),
-                                SerializedItem::new("Terminal", 2),
+                                SerializedItem::new("Terminal", 1, false),
+                                SerializedItem::new("Terminal", 2, true),
                             ],
                             false,
                         )),
                         SerializedPaneGroup::Pane(SerializedPane::new(
                             vec![
-                                SerializedItem::new("Terminal", 4),
-                                SerializedItem::new("Terminal", 3),
+                                SerializedItem::new("Terminal", 4, false),
+                                SerializedItem::new("Terminal", 3, true),
                             ],
                             true,
                         )),
@@ -788,8 +789,8 @@ mod tests {
                 },
                 SerializedPaneGroup::Pane(SerializedPane::new(
                     vec![
-                        SerializedItem::new("Terminal", 5),
-                        SerializedItem::new("Terminal", 6),
+                        SerializedItem::new("Terminal", 5, false),
+                        SerializedItem::new("Terminal", 6, true),
                     ],
                     false,
                 )),
@@ -807,15 +808,15 @@ mod tests {
             children: vec![
                 SerializedPaneGroup::Pane(SerializedPane::new(
                     vec![
-                        SerializedItem::new("Terminal", 1),
-                        SerializedItem::new("Terminal", 2),
+                        SerializedItem::new("Terminal", 1, false),
+                        SerializedItem::new("Terminal", 2, true),
                     ],
                     false,
                 )),
                 SerializedPaneGroup::Pane(SerializedPane::new(
                     vec![
-                        SerializedItem::new("Terminal", 4),
-                        SerializedItem::new("Terminal", 3),
+                        SerializedItem::new("Terminal", 4, true),
+                        SerializedItem::new("Terminal", 3, false),
                     ],
                     true,
                 )),

crates/workspace/src/persistence/model.rs 🔗

@@ -147,7 +147,8 @@ impl SerializedPane {
         workspace: &ViewHandle<Workspace>,
         cx: &mut AsyncAppContext,
     ) {
-        for item in self.children.iter() {
+        let mut active_item_index = None;
+        for (index, item) in self.children.iter().enumerate() {
             let project = project.clone();
             let item_handle = pane_handle
                 .update(cx, |_, cx| {
@@ -174,6 +175,16 @@ impl SerializedPane {
                     Pane::add_item(workspace, &pane_handle, item_handle, false, false, None, cx);
                 })
             }
+
+            if item.active {
+                active_item_index = Some(index);
+            }
+        }
+
+        if let Some(active_item_index) = active_item_index {
+            pane_handle.update(cx, |pane, cx| {
+                pane.activate_item(active_item_index, false, false, cx);
+            })
         }
     }
 }
@@ -186,13 +197,15 @@ pub type ItemId = usize;
 pub struct SerializedItem {
     pub kind: Arc<str>,
     pub item_id: ItemId,
+    pub active: bool,
 }
 
 impl SerializedItem {
-    pub fn new(kind: impl AsRef<str>, item_id: ItemId) -> Self {
+    pub fn new(kind: impl AsRef<str>, item_id: ItemId, active: bool) -> Self {
         Self {
             kind: Arc::from(kind.as_ref()),
             item_id,
+            active,
         }
     }
 }
@@ -203,6 +216,7 @@ impl Default for SerializedItem {
         SerializedItem {
             kind: Arc::from("Terminal"),
             item_id: 100000,
+            active: false,
         }
     }
 }
@@ -210,7 +224,8 @@ impl Default for SerializedItem {
 impl Bind for &SerializedItem {
     fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
         let next_index = statement.bind(self.kind.clone(), start_index)?;
-        statement.bind(self.item_id, next_index)
+        let next_index = statement.bind(self.item_id, next_index)?;
+        statement.bind(self.active, next_index)
     }
 }
 
@@ -218,7 +233,15 @@ impl Column for SerializedItem {
     fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
         let (kind, next_index) = Arc::<str>::column(statement, start_index)?;
         let (item_id, next_index) = ItemId::column(statement, next_index)?;
-        Ok((SerializedItem { kind, item_id }, next_index))
+        let (active, next_index) = bool::column(statement, next_index)?;
+        Ok((
+            SerializedItem {
+                kind,
+                item_id,
+                active,
+            },
+            next_index,
+        ))
     }
 }
 

crates/workspace/src/workspace.rs 🔗

@@ -2292,12 +2292,14 @@ impl Workspace {
         ) -> SerializedPane {
             let (items, active) = {
                 let pane = pane_handle.read(cx);
+                let active_item_id = pane.active_item().map(|item| item.id());
                 (
                     pane.items()
                         .filter_map(|item_handle| {
                             Some(SerializedItem {
                                 kind: Arc::from(item_handle.serialized_item_kind()?),
                                 item_id: item_handle.id(),
+                                active: Some(item_handle.id()) == active_item_id,
                             })
                         })
                         .collect::<Vec<_>>(),
@@ -2308,8 +2310,6 @@ impl Workspace {
             SerializedPane::new(items, active)
         }
 
-        let dock_pane = serialize_pane_handle(self.dock.pane(), cx);
-
         fn build_serialized_pane_group(
             pane_group: &Member,
             cx: &AppContext,
@@ -2327,19 +2327,25 @@ impl Workspace {
                 }
             }
         }
-        let center_group = build_serialized_pane_group(&self.center.root, cx);
-
-        let serialized_workspace = SerializedWorkspace {
-            id: self.database_id,
-            location: self.location(cx),
-            dock_position: self.dock.position(),
-            dock_pane,
-            center_group,
-        };
 
-        cx.background()
-            .spawn(persistence::DB.save_workspace(serialized_workspace))
-            .detach();
+        let location = self.location(cx);
+
+        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);
+
+            let serialized_workspace = SerializedWorkspace {
+                id: self.database_id,
+                location: self.location(cx),
+                dock_position: self.dock.position(),
+                dock_pane,
+                center_group,
+            };
+
+            cx.background()
+                .spawn(persistence::DB.save_workspace(serialized_workspace))
+                .detach();
+        }
     }
 
     fn load_from_serialized_workspace(
@@ -2380,13 +2386,11 @@ impl Workspace {
                     Dock::set_dock_position(workspace, serialized_workspace.dock_position, cx);
 
                     if let Some(active_pane) = active_pane {
+                        // Change the focus to the workspace first so that we retrigger focus in on the pane.
+                        cx.focus_self();
                         cx.focus(active_pane);
                     }
 
-                    if workspace.items(cx).next().is_none() {
-                        cx.dispatch_action(NewFile);
-                    }
-
                     cx.notify();
                 });
             }