WIP - Reopen closed items when going back in nav history

This commit is contained in:
Max Brunsfeld 2022-01-17 10:46:47 -08:00
parent ea624c6cde
commit e43d33cdad
4 changed files with 87 additions and 54 deletions

1
Cargo.lock generated
View file

@ -5677,6 +5677,7 @@ dependencies = [
"project", "project",
"serde_json", "serde_json",
"theme", "theme",
"util",
] ]
[[package]] [[package]]

View file

@ -17,6 +17,7 @@ gpui = { path = "../gpui" }
language = { path = "../language" } language = { path = "../language" }
project = { path = "../project" } project = { path = "../project" }
theme = { path = "../theme" } theme = { path = "../theme" }
util = { path = "../util" }
anyhow = "1.0.38" anyhow = "1.0.38"
log = "0.4" log = "0.4"
parking_lot = "0.11.1" parking_lot = "0.11.1"

View file

@ -12,6 +12,7 @@ use gpui::{
use postage::watch; use postage::watch;
use project::ProjectPath; use project::ProjectPath;
use std::{any::Any, cell::RefCell, cmp, mem, rc::Rc}; use std::{any::Any, cell::RefCell, cmp, mem, rc::Rc};
use util::TryFutureExt;
action!(Split, SplitDirection); action!(Split, SplitDirection);
action!(ActivateItem, usize); action!(ActivateItem, usize);
@ -114,29 +115,51 @@ impl Pane {
cx.emit(Event::Activate); cx.emit(Event::Activate);
} }
pub fn go_back(&mut self, _: &GoBack, cx: &mut ViewContext<Self>) { pub fn go_back(workspace: &mut Workspace, _: &GoBack, cx: &mut ViewContext<Workspace>) {
if self.navigation.0.borrow().backward_stack.is_empty() { let project_path = workspace.active_pane().update(cx, |pane, cx| {
return; 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() { pane.active_item_index = index;
self.navigation.0.borrow_mut().mode = NavigationHistoryMode::GoingBack; drop(navigation);
item_view.deactivated(cx); pane.focus_active_item(cx);
self.navigation.0.borrow_mut().mode = NavigationHistoryMode::Normal; cx.notify();
} } else {
return navigation.paths_by_item.get(&entry.item_view.id()).cloned();
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();
} }
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<Self>) { pub fn close_item(&mut self, item_view_id: usize, cx: &mut ViewContext<Self>) {
let mut item_ix = 0; let mut item_ix = 0;
self.item_views.retain(|(item_id, item)| { self.item_views.retain(|(_, item_view)| {
if item.id() == item_view_id { if item_view.id() == item_view_id {
let mut navigation = self.navigation.0.borrow_mut(); let mut navigation = self.navigation.0.borrow_mut();
if let Some(path) = item.project_path(cx) { if let Some(path) = item_view.project_path(cx) {
navigation.paths_by_item.insert(*item_id, path); navigation.paths_by_item.insert(item_view.id(), path);
} else { } else {
navigation.paths_by_item.remove(item_id); navigation.paths_by_item.remove(&item_view.id());
} }
if item_ix == self.active_item_index { if item_ix == self.active_item_index {
item.deactivated(cx); item_view.deactivated(cx);
} }
item_ix += 1; item_ix += 1;
false false

View file

@ -227,6 +227,7 @@ pub trait ItemViewHandle {
} }
pub trait WeakItemViewHandle { pub trait WeakItemViewHandle {
fn id(&self) -> usize;
fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn ItemViewHandle>>; fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn ItemViewHandle>>;
} }
@ -418,6 +419,10 @@ impl Clone for Box<dyn ItemHandle> {
} }
impl<T: ItemView> WeakItemViewHandle for WeakViewHandle<T> { impl<T: ItemView> WeakItemViewHandle for WeakViewHandle<T> {
fn id(&self) -> usize {
self.id()
}
fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn ItemViewHandle>> { fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn ItemViewHandle>> {
self.upgrade(cx) self.upgrade(cx)
.map(|v| Box::new(v) as Box<dyn ItemViewHandle>) .map(|v| Box::new(v) as Box<dyn ItemViewHandle>)
@ -747,40 +752,15 @@ impl Workspace {
} }
} }
#[must_use]
pub fn open_path( pub fn open_path(
&mut self, &mut self,
path: ProjectPath, path: ProjectPath,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Task<Result<Box<dyn ItemViewHandle>, Arc<anyhow::Error>>> { ) -> Task<Result<Box<dyn ItemViewHandle>, Arc<anyhow::Error>>> {
if let Some(existing_item) = self.item_for_path(&path, cx) { let load_task = self.load_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 pane = self.active_pane().clone().downgrade(); let pane = self.active_pane().clone().downgrade();
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
let item = open_task.await?; let item = load_task.await?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
let pane = pane let pane = pane
.upgrade(&cx) .upgrade(&cx)
@ -790,6 +770,34 @@ impl Workspace {
}) })
} }
pub fn load_path(
&mut self,
path: ProjectPath,
cx: &mut ViewContext<Self>,
) -> Task<Result<Box<dyn ItemHandle>>> {
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<Box<dyn ItemHandle>> { fn item_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option<Box<dyn ItemHandle>> {
self.items self.items
.iter() .iter()