diff --git a/Cargo.lock b/Cargo.lock index 119515de8b..03faaaf561 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5677,6 +5677,7 @@ dependencies = [ "project", "serde_json", "theme", + "util", ] [[package]] diff --git a/crates/workspace/Cargo.toml b/crates/workspace/Cargo.toml index 74a9aea733..f3ea330ca3 100644 --- a/crates/workspace/Cargo.toml +++ b/crates/workspace/Cargo.toml @@ -17,6 +17,7 @@ gpui = { path = "../gpui" } language = { path = "../language" } project = { path = "../project" } theme = { path = "../theme" } +util = { path = "../util" } anyhow = "1.0.38" log = "0.4" parking_lot = "0.11.1" diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index c7ea004956..6fb35ba786 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -12,6 +12,7 @@ use gpui::{ use postage::watch; use project::ProjectPath; use std::{any::Any, cell::RefCell, cmp, mem, rc::Rc}; +use util::TryFutureExt; action!(Split, SplitDirection); action!(ActivateItem, usize); @@ -114,29 +115,51 @@ impl Pane { cx.emit(Event::Activate); } - pub fn go_back(&mut self, _: &GoBack, cx: &mut ViewContext) { - if self.navigation.0.borrow().backward_stack.is_empty() { - return; - } + pub fn go_back(workspace: &mut Workspace, _: &GoBack, cx: &mut ViewContext) { + let project_path = workspace.active_pane().update(cx, |pane, cx| { + let mut navigation = pane.navigation.0.borrow_mut(); + if let Some(entry) = navigation.backward_stack.pop() { + if let Some(index) = entry + .item_view + .upgrade(cx) + .and_then(|v| pane.index_for_item_view(v.as_ref())) + { + if let Some(item_view) = pane.active_item() { + pane.navigation.0.borrow_mut().mode = NavigationHistoryMode::GoingBack; + item_view.deactivated(cx); + pane.navigation.0.borrow_mut().mode = NavigationHistoryMode::Normal; + } - if let Some(item_view) = self.active_item() { - self.navigation.0.borrow_mut().mode = NavigationHistoryMode::GoingBack; - item_view.deactivated(cx); - self.navigation.0.borrow_mut().mode = NavigationHistoryMode::Normal; - } - - let mut navigation = self.navigation.0.borrow_mut(); - if let Some(entry) = navigation.backward_stack.pop() { - if let Some(index) = entry - .item_view - .upgrade(cx) - .and_then(|v| self.index_for_item_view(v.as_ref())) - { - self.active_item_index = index; - drop(navigation); - self.focus_active_item(cx); - cx.notify(); + pane.active_item_index = index; + drop(navigation); + pane.focus_active_item(cx); + cx.notify(); + } else { + return navigation.paths_by_item.get(&entry.item_view.id()).cloned(); + } } + + None + }); + + if let Some(project_path) = project_path { + let task = workspace.load_path(project_path, cx); + cx.spawn(|workspace, mut cx| { + async move { + let item = task.await?; + workspace.update(&mut cx, |workspace, cx| { + let pane = workspace.active_pane().clone(); + pane.update(cx, |pane, cx| { + pane.navigation.0.borrow_mut().mode = NavigationHistoryMode::GoingBack; + pane.open_item(item, workspace, cx); + pane.navigation.0.borrow_mut().mode = NavigationHistoryMode::Normal; + }); + }); + Ok(()) + } + .log_err() + }) + .detach(); } } @@ -268,17 +291,17 @@ impl Pane { pub fn close_item(&mut self, item_view_id: usize, cx: &mut ViewContext) { let mut item_ix = 0; - self.item_views.retain(|(item_id, item)| { - if item.id() == item_view_id { + self.item_views.retain(|(_, item_view)| { + if item_view.id() == item_view_id { let mut navigation = self.navigation.0.borrow_mut(); - if let Some(path) = item.project_path(cx) { - navigation.paths_by_item.insert(*item_id, path); + if let Some(path) = item_view.project_path(cx) { + navigation.paths_by_item.insert(item_view.id(), path); } else { - navigation.paths_by_item.remove(item_id); + navigation.paths_by_item.remove(&item_view.id()); } if item_ix == self.active_item_index { - item.deactivated(cx); + item_view.deactivated(cx); } item_ix += 1; false diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 9f65062bf9..99ef8764e8 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -227,6 +227,7 @@ pub trait ItemViewHandle { } pub trait WeakItemViewHandle { + fn id(&self) -> usize; fn upgrade(&self, cx: &AppContext) -> Option>; } @@ -418,6 +419,10 @@ impl Clone for Box { } impl WeakItemViewHandle for WeakViewHandle { + fn id(&self) -> usize { + self.id() + } + fn upgrade(&self, cx: &AppContext) -> Option> { self.upgrade(cx) .map(|v| Box::new(v) as Box) @@ -747,40 +752,15 @@ impl Workspace { } } - #[must_use] pub fn open_path( &mut self, path: ProjectPath, cx: &mut ViewContext, ) -> Task, Arc>> { - if let Some(existing_item) = self.item_for_path(&path, cx) { - return Task::ready(Ok(self.open_item(existing_item, cx))); - } - - let worktree = match self.project.read(cx).worktree_for_id(path.worktree_id, cx) { - Some(worktree) => worktree, - None => { - return Task::ready(Err(Arc::new(anyhow!( - "worktree {} does not exist", - path.worktree_id - )))); - } - }; - - let project_path = path.clone(); - let path_openers = self.path_openers.clone(); - let open_task = worktree.update(cx, |worktree, cx| { - for opener in path_openers.iter() { - if let Some(task) = opener.open(worktree, project_path.clone(), cx) { - return task; - } - } - Task::ready(Err(anyhow!("no opener found for path {:?}", project_path))) - }); - + let load_task = self.load_path(path, cx); let pane = self.active_pane().clone().downgrade(); cx.spawn(|this, mut cx| async move { - let item = open_task.await?; + let item = load_task.await?; this.update(&mut cx, |this, cx| { let pane = pane .upgrade(&cx) @@ -790,6 +770,34 @@ impl Workspace { }) } + pub fn load_path( + &mut self, + path: ProjectPath, + cx: &mut ViewContext, + ) -> Task>> { + if let Some(existing_item) = self.item_for_path(&path, cx) { + return Task::ready(Ok(existing_item)); + } + + let worktree = match self.project.read(cx).worktree_for_id(path.worktree_id, cx) { + Some(worktree) => worktree, + None => { + return Task::ready(Err(anyhow!("worktree {} does not exist", path.worktree_id))); + } + }; + + let project_path = path.clone(); + let path_openers = self.path_openers.clone(); + worktree.update(cx, |worktree, cx| { + for opener in path_openers.iter() { + if let Some(task) = opener.open(worktree, project_path.clone(), cx) { + return task; + } + } + Task::ready(Err(anyhow!("no opener found for path {:?}", project_path))) + }) + } + fn item_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option> { self.items .iter()