Move history navigation logic to Workspace
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
6d3464fd1f
commit
88eb2b2163
8 changed files with 333 additions and 333 deletions
|
@ -6608,7 +6608,7 @@ async fn test_basic_following(
|
||||||
// When client A navigates back and forth, client B does so as well.
|
// When client A navigates back and forth, client B does so as well.
|
||||||
workspace_a
|
workspace_a
|
||||||
.update(cx_a, |workspace, cx| {
|
.update(cx_a, |workspace, cx| {
|
||||||
workspace::Pane::go_back(workspace, None, cx)
|
workspace.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -6619,7 +6619,7 @@ async fn test_basic_following(
|
||||||
|
|
||||||
workspace_a
|
workspace_a
|
||||||
.update(cx_a, |workspace, cx| {
|
.update(cx_a, |workspace, cx| {
|
||||||
workspace::Pane::go_back(workspace, None, cx)
|
workspace.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -6630,7 +6630,7 @@ async fn test_basic_following(
|
||||||
|
|
||||||
workspace_a
|
workspace_a
|
||||||
.update(cx_a, |workspace, cx| {
|
.update(cx_a, |workspace, cx| {
|
||||||
workspace::Pane::go_forward(workspace, None, cx)
|
workspace.go_forward(workspace.active_pane().downgrade(), cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -4931,12 +4931,12 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_nav_history(
|
fn push_to_nav_history(
|
||||||
&self,
|
&mut self,
|
||||||
cursor_anchor: Anchor,
|
cursor_anchor: Anchor,
|
||||||
new_position: Option<Point>,
|
new_position: Option<Point>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
if let Some(nav_history) = &self.nav_history {
|
if let Some(nav_history) = self.nav_history.as_mut() {
|
||||||
let buffer = self.buffer.read(cx).read(cx);
|
let buffer = self.buffer.read(cx).read(cx);
|
||||||
let cursor_position = cursor_anchor.to_point(&buffer);
|
let cursor_position = cursor_anchor.to_point(&buffer);
|
||||||
let scroll_state = self.scroll_manager.anchor();
|
let scroll_state = self.scroll_manager.anchor();
|
||||||
|
|
|
@ -39,7 +39,6 @@ use std::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use theme::{Theme, ThemeSettings};
|
use theme::{Theme, ThemeSettings};
|
||||||
use util::ResultExt;
|
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, PartialEq)]
|
#[derive(Clone, Deserialize, PartialEq)]
|
||||||
pub struct ActivateItem(pub usize);
|
pub struct ActivateItem(pub usize);
|
||||||
|
@ -74,6 +73,8 @@ actions!(
|
||||||
CloseItemsToTheLeft,
|
CloseItemsToTheLeft,
|
||||||
CloseItemsToTheRight,
|
CloseItemsToTheRight,
|
||||||
CloseAllItems,
|
CloseAllItems,
|
||||||
|
GoBack,
|
||||||
|
GoForward,
|
||||||
ReopenClosedItem,
|
ReopenClosedItem,
|
||||||
SplitLeft,
|
SplitLeft,
|
||||||
SplitUp,
|
SplitUp,
|
||||||
|
@ -82,19 +83,7 @@ actions!(
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, PartialEq)]
|
impl_actions!(pane, [ActivateItem]);
|
||||||
pub struct GoBack {
|
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub pane: Option<WeakViewHandle<Pane>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, PartialEq)]
|
|
||||||
pub struct GoForward {
|
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub pane: Option<WeakViewHandle<Pane>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_actions!(pane, [GoBack, GoForward, ActivateItem]);
|
|
||||||
|
|
||||||
const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
|
const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
|
||||||
|
|
||||||
|
@ -124,15 +113,6 @@ pub fn init(cx: &mut AppContext) {
|
||||||
cx.add_action(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx));
|
cx.add_action(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx));
|
||||||
cx.add_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx));
|
cx.add_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx));
|
||||||
cx.add_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx));
|
cx.add_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx));
|
||||||
cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| {
|
|
||||||
Pane::reopen_closed_item(workspace, cx).detach();
|
|
||||||
});
|
|
||||||
cx.add_action(|workspace: &mut Workspace, action: &GoBack, cx| {
|
|
||||||
Pane::go_back(workspace, action.pane.clone(), cx).detach();
|
|
||||||
});
|
|
||||||
cx.add_action(|workspace: &mut Workspace, action: &GoForward, cx| {
|
|
||||||
Pane::go_forward(workspace, action.pane.clone(), cx).detach();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -155,7 +135,7 @@ pub struct Pane {
|
||||||
active_item_index: usize,
|
active_item_index: usize,
|
||||||
last_focused_view_by_item: HashMap<usize, AnyWeakViewHandle>,
|
last_focused_view_by_item: HashMap<usize, AnyWeakViewHandle>,
|
||||||
autoscroll: bool,
|
autoscroll: bool,
|
||||||
nav_history: Rc<RefCell<NavHistory>>,
|
nav_history: NavHistory,
|
||||||
toolbar: ViewHandle<Toolbar>,
|
toolbar: ViewHandle<Toolbar>,
|
||||||
tab_bar_context_menu: TabBarContextMenu,
|
tab_bar_context_menu: TabBarContextMenu,
|
||||||
tab_context_menu: ViewHandle<ContextMenu>,
|
tab_context_menu: ViewHandle<ContextMenu>,
|
||||||
|
@ -165,18 +145,18 @@ pub struct Pane {
|
||||||
has_focus: bool,
|
has_focus: bool,
|
||||||
can_drop: Rc<dyn Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool>,
|
can_drop: Rc<dyn Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool>,
|
||||||
can_split: bool,
|
can_split: bool,
|
||||||
can_navigate: bool,
|
|
||||||
render_tab_bar_buttons: Rc<dyn Fn(&mut Pane, &mut ViewContext<Pane>) -> AnyElement<Pane>>,
|
render_tab_bar_buttons: Rc<dyn Fn(&mut Pane, &mut ViewContext<Pane>) -> AnyElement<Pane>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ItemNavHistory {
|
pub struct ItemNavHistory {
|
||||||
history: Rc<RefCell<NavHistory>>,
|
history: NavHistory,
|
||||||
item: Rc<dyn WeakItemHandle>,
|
item: Rc<dyn WeakItemHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PaneNavHistory(Rc<RefCell<NavHistory>>);
|
#[derive(Clone)]
|
||||||
|
pub struct NavHistory(Rc<RefCell<NavHistoryState>>);
|
||||||
|
|
||||||
struct NavHistory {
|
struct NavHistoryState {
|
||||||
mode: NavigationMode,
|
mode: NavigationMode,
|
||||||
backward_stack: VecDeque<NavigationEntry>,
|
backward_stack: VecDeque<NavigationEntry>,
|
||||||
forward_stack: VecDeque<NavigationEntry>,
|
forward_stack: VecDeque<NavigationEntry>,
|
||||||
|
@ -187,7 +167,7 @@ struct NavHistory {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
enum NavigationMode {
|
pub enum NavigationMode {
|
||||||
Normal,
|
Normal,
|
||||||
GoingBack,
|
GoingBack,
|
||||||
GoingForward,
|
GoingForward,
|
||||||
|
@ -262,7 +242,7 @@ impl Pane {
|
||||||
active_item_index: 0,
|
active_item_index: 0,
|
||||||
last_focused_view_by_item: Default::default(),
|
last_focused_view_by_item: Default::default(),
|
||||||
autoscroll: false,
|
autoscroll: false,
|
||||||
nav_history: Rc::new(RefCell::new(NavHistory {
|
nav_history: NavHistory(Rc::new(RefCell::new(NavHistoryState {
|
||||||
mode: NavigationMode::Normal,
|
mode: NavigationMode::Normal,
|
||||||
backward_stack: Default::default(),
|
backward_stack: Default::default(),
|
||||||
forward_stack: Default::default(),
|
forward_stack: Default::default(),
|
||||||
|
@ -270,7 +250,7 @@ impl Pane {
|
||||||
paths_by_item: Default::default(),
|
paths_by_item: Default::default(),
|
||||||
pane: handle.clone(),
|
pane: handle.clone(),
|
||||||
next_timestamp,
|
next_timestamp,
|
||||||
})),
|
}))),
|
||||||
toolbar: cx.add_view(|_| Toolbar::new(handle)),
|
toolbar: cx.add_view(|_| Toolbar::new(handle)),
|
||||||
tab_bar_context_menu: TabBarContextMenu {
|
tab_bar_context_menu: TabBarContextMenu {
|
||||||
kind: TabBarContextMenuKind::New,
|
kind: TabBarContextMenuKind::New,
|
||||||
|
@ -283,7 +263,6 @@ impl Pane {
|
||||||
has_focus: false,
|
has_focus: false,
|
||||||
can_drop: Rc::new(|_, _| true),
|
can_drop: Rc::new(|_, _| true),
|
||||||
can_split: true,
|
can_split: true,
|
||||||
can_navigate: true,
|
|
||||||
render_tab_bar_buttons: Rc::new(|pane, cx| {
|
render_tab_bar_buttons: Rc::new(|pane, cx| {
|
||||||
Flex::row()
|
Flex::row()
|
||||||
// New menu
|
// New menu
|
||||||
|
@ -339,6 +318,10 @@ impl Pane {
|
||||||
self.has_focus
|
self.has_focus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn active_item_index(&self) -> usize {
|
||||||
|
self.active_item_index
|
||||||
|
}
|
||||||
|
|
||||||
pub fn on_can_drop<F>(&mut self, can_drop: F)
|
pub fn on_can_drop<F>(&mut self, can_drop: F)
|
||||||
where
|
where
|
||||||
F: 'static + Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool,
|
F: 'static + Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool,
|
||||||
|
@ -352,7 +335,6 @@ impl Pane {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_can_navigate(&mut self, can_navigate: bool, cx: &mut ViewContext<Self>) {
|
pub fn set_can_navigate(&mut self, can_navigate: bool, cx: &mut ViewContext<Self>) {
|
||||||
self.can_navigate = can_navigate;
|
|
||||||
self.toolbar.update(cx, |toolbar, cx| {
|
self.toolbar.update(cx, |toolbar, cx| {
|
||||||
toolbar.set_can_navigate(can_navigate, cx);
|
toolbar.set_can_navigate(can_navigate, cx);
|
||||||
});
|
});
|
||||||
|
@ -374,164 +356,34 @@ impl Pane {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nav_history(&self) -> PaneNavHistory {
|
pub fn nav_history(&self) -> &NavHistory {
|
||||||
PaneNavHistory(self.nav_history.clone())
|
&self.nav_history
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn go_back(
|
pub fn nav_history_mut(&mut self) -> &mut NavHistory {
|
||||||
workspace: &mut Workspace,
|
&mut self.nav_history
|
||||||
pane: Option<WeakViewHandle<Pane>>,
|
|
||||||
cx: &mut ViewContext<Workspace>,
|
|
||||||
) -> Task<Result<()>> {
|
|
||||||
Self::navigate_history(
|
|
||||||
workspace,
|
|
||||||
pane.unwrap_or_else(|| workspace.active_pane().downgrade()),
|
|
||||||
NavigationMode::GoingBack,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn go_forward(
|
|
||||||
workspace: &mut Workspace,
|
|
||||||
pane: Option<WeakViewHandle<Pane>>,
|
|
||||||
cx: &mut ViewContext<Workspace>,
|
|
||||||
) -> Task<Result<()>> {
|
|
||||||
Self::navigate_history(
|
|
||||||
workspace,
|
|
||||||
pane.unwrap_or_else(|| workspace.active_pane().downgrade()),
|
|
||||||
NavigationMode::GoingForward,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reopen_closed_item(
|
|
||||||
workspace: &mut Workspace,
|
|
||||||
cx: &mut ViewContext<Workspace>,
|
|
||||||
) -> Task<Result<()>> {
|
|
||||||
Self::navigate_history(
|
|
||||||
workspace,
|
|
||||||
workspace.active_pane().downgrade(),
|
|
||||||
NavigationMode::ReopeningClosedItem,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_history(&mut self) {
|
pub fn disable_history(&mut self) {
|
||||||
self.nav_history.borrow_mut().disable();
|
self.nav_history.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_history(&mut self) {
|
pub fn enable_history(&mut self) {
|
||||||
self.nav_history.borrow_mut().enable();
|
self.nav_history.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_navigate_backward(&self) -> bool {
|
pub fn can_navigate_backward(&self) -> bool {
|
||||||
!self.nav_history.borrow().backward_stack.is_empty()
|
!self.nav_history.0.borrow().backward_stack.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_navigate_forward(&self) -> bool {
|
pub fn can_navigate_forward(&self) -> bool {
|
||||||
!self.nav_history.borrow().forward_stack.is_empty()
|
!self.nav_history.0.borrow().forward_stack.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn history_updated(&mut self, cx: &mut ViewContext<Self>) {
|
fn history_updated(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
self.toolbar.update(cx, |_, cx| cx.notify());
|
self.toolbar.update(cx, |_, cx| cx.notify());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn navigate_history(
|
|
||||||
workspace: &mut Workspace,
|
|
||||||
pane: WeakViewHandle<Pane>,
|
|
||||||
mode: NavigationMode,
|
|
||||||
cx: &mut ViewContext<Workspace>,
|
|
||||||
) -> Task<Result<()>> {
|
|
||||||
let to_load = if let Some(pane) = pane.upgrade(cx) {
|
|
||||||
if !pane.read(cx).can_navigate {
|
|
||||||
return Task::ready(Ok(()));
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.focus(&pane);
|
|
||||||
|
|
||||||
pane.update(cx, |pane, cx| {
|
|
||||||
loop {
|
|
||||||
// Retrieve the weak item handle from the history.
|
|
||||||
let entry = pane.nav_history.borrow_mut().pop(mode, cx)?;
|
|
||||||
|
|
||||||
// If the item is still present in this pane, then activate it.
|
|
||||||
if let Some(index) = entry
|
|
||||||
.item
|
|
||||||
.upgrade(cx)
|
|
||||||
.and_then(|v| pane.index_for_item(v.as_ref()))
|
|
||||||
{
|
|
||||||
let prev_active_item_index = pane.active_item_index;
|
|
||||||
pane.nav_history.borrow_mut().set_mode(mode);
|
|
||||||
pane.activate_item(index, true, true, cx);
|
|
||||||
pane.nav_history
|
|
||||||
.borrow_mut()
|
|
||||||
.set_mode(NavigationMode::Normal);
|
|
||||||
|
|
||||||
let mut navigated = prev_active_item_index != pane.active_item_index;
|
|
||||||
if let Some(data) = entry.data {
|
|
||||||
navigated |= pane.active_item()?.navigate(data, cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if navigated {
|
|
||||||
break None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the item is no longer present in this pane, then retrieve its
|
|
||||||
// project path in order to reopen it.
|
|
||||||
else {
|
|
||||||
break pane
|
|
||||||
.nav_history
|
|
||||||
.borrow()
|
|
||||||
.paths_by_item
|
|
||||||
.get(&entry.item.id())
|
|
||||||
.cloned()
|
|
||||||
.map(|(project_path, _)| (project_path, entry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some((project_path, entry)) = to_load {
|
|
||||||
// If the item was no longer present, then load it again from its previous path.
|
|
||||||
let task = workspace.load_path(project_path, cx);
|
|
||||||
cx.spawn(|workspace, mut cx| async move {
|
|
||||||
let task = task.await;
|
|
||||||
let mut navigated = false;
|
|
||||||
if let Some((project_entry_id, build_item)) = task.log_err() {
|
|
||||||
let prev_active_item_id = pane.update(&mut cx, |pane, _| {
|
|
||||||
pane.nav_history.borrow_mut().set_mode(mode);
|
|
||||||
pane.active_item().map(|p| p.id())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
pane.update(&mut cx, |pane, cx| {
|
|
||||||
let item = pane.open_item(project_entry_id, true, cx, build_item);
|
|
||||||
navigated |= Some(item.id()) != prev_active_item_id;
|
|
||||||
pane.nav_history
|
|
||||||
.borrow_mut()
|
|
||||||
.set_mode(NavigationMode::Normal);
|
|
||||||
if let Some(data) = entry.data {
|
|
||||||
navigated |= item.navigate(data, cx);
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !navigated {
|
|
||||||
workspace
|
|
||||||
.update(&mut cx, |workspace, cx| {
|
|
||||||
Self::navigate_history(workspace, pane, mode, cx)
|
|
||||||
})?
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Task::ready(Ok(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn open_item(
|
pub(crate) fn open_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
project_entry_id: ProjectEntryId,
|
project_entry_id: ProjectEntryId,
|
||||||
|
@ -573,6 +425,7 @@ impl Pane {
|
||||||
if let Some(project_path) = project.path_for_entry(entry_id, cx) {
|
if let Some(project_path) = project.path_for_entry(entry_id, cx) {
|
||||||
let abs_path = project.absolute_path(&project_path, cx);
|
let abs_path = project.absolute_path(&project_path, cx);
|
||||||
self.nav_history
|
self.nav_history
|
||||||
|
.0
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.paths_by_item
|
.paths_by_item
|
||||||
.insert(item.id(), (project_path, abs_path));
|
.insert(item.id(), (project_path, abs_path));
|
||||||
|
@ -713,7 +566,7 @@ impl Pane {
|
||||||
if index < self.items.len() {
|
if index < self.items.len() {
|
||||||
let prev_active_item_ix = mem::replace(&mut self.active_item_index, index);
|
let prev_active_item_ix = mem::replace(&mut self.active_item_index, index);
|
||||||
if prev_active_item_ix != self.active_item_index
|
if prev_active_item_ix != self.active_item_index
|
||||||
|| matches!(self.nav_history.borrow().mode, GoingBack | GoingForward)
|
|| matches!(self.nav_history.mode(), GoingBack | GoingForward)
|
||||||
{
|
{
|
||||||
if let Some(prev_item) = self.items.get(prev_active_item_ix) {
|
if let Some(prev_item) = self.items.get(prev_active_item_ix) {
|
||||||
prev_item.deactivated(cx);
|
prev_item.deactivated(cx);
|
||||||
|
@ -981,27 +834,26 @@ impl Pane {
|
||||||
self.active_item_index -= 1;
|
self.active_item_index -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.nav_history
|
self.nav_history.set_mode(NavigationMode::ClosingItem);
|
||||||
.borrow_mut()
|
|
||||||
.set_mode(NavigationMode::ClosingItem);
|
|
||||||
item.deactivated(cx);
|
item.deactivated(cx);
|
||||||
self.nav_history
|
self.nav_history.set_mode(NavigationMode::Normal);
|
||||||
.borrow_mut()
|
|
||||||
.set_mode(NavigationMode::Normal);
|
|
||||||
|
|
||||||
if let Some(path) = item.project_path(cx) {
|
if let Some(path) = item.project_path(cx) {
|
||||||
let abs_path = self
|
let abs_path = self
|
||||||
.nav_history
|
.nav_history
|
||||||
|
.0
|
||||||
.borrow()
|
.borrow()
|
||||||
.paths_by_item
|
.paths_by_item
|
||||||
.get(&item.id())
|
.get(&item.id())
|
||||||
.and_then(|(_, abs_path)| abs_path.clone());
|
.and_then(|(_, abs_path)| abs_path.clone());
|
||||||
self.nav_history
|
self.nav_history
|
||||||
|
.0
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.paths_by_item
|
.paths_by_item
|
||||||
.insert(item.id(), (path, abs_path));
|
.insert(item.id(), (path, abs_path));
|
||||||
} else {
|
} else {
|
||||||
self.nav_history
|
self.nav_history
|
||||||
|
.0
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.paths_by_item
|
.paths_by_item
|
||||||
.remove(&item.id());
|
.remove(&item.id());
|
||||||
|
@ -1249,7 +1101,7 @@ impl Pane {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
self.remove_item(item_index_to_delete, false, cx);
|
self.remove_item(item_index_to_delete, false, cx);
|
||||||
self.nav_history.borrow_mut().remove_item(item_id);
|
self.nav_history.remove_item(item_id);
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
@ -1719,7 +1571,7 @@ impl View for Pane {
|
||||||
let pane = cx.weak_handle();
|
let pane = cx.weak_handle();
|
||||||
cx.window_context().defer(move |cx| {
|
cx.window_context().defer(move |cx| {
|
||||||
workspace.update(cx, |workspace, cx| {
|
workspace.update(cx, |workspace, cx| {
|
||||||
Pane::go_back(workspace, Some(pane), cx).detach_and_log_err(cx)
|
workspace.go_back(pane, cx).detach_and_log_err(cx)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1731,7 +1583,7 @@ impl View for Pane {
|
||||||
let pane = cx.weak_handle();
|
let pane = cx.weak_handle();
|
||||||
cx.window_context().defer(move |cx| {
|
cx.window_context().defer(move |cx| {
|
||||||
workspace.update(cx, |workspace, cx| {
|
workspace.update(cx, |workspace, cx| {
|
||||||
Pane::go_forward(workspace, Some(pane), cx).detach_and_log_err(cx)
|
workspace.go_forward(pane, cx).detach_and_log_err(cx)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1786,122 +1638,20 @@ impl View for Pane {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemNavHistory {
|
impl ItemNavHistory {
|
||||||
pub fn push<D: 'static + Any>(&self, data: Option<D>, cx: &mut WindowContext) {
|
pub fn push<D: 'static + Any>(&mut self, data: Option<D>, cx: &mut WindowContext) {
|
||||||
self.history.borrow_mut().push(data, self.item.clone(), cx);
|
self.history.push(data, self.item.clone(), cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_backward(&self, cx: &mut WindowContext) -> Option<NavigationEntry> {
|
pub fn pop_backward(&mut self, cx: &mut WindowContext) -> Option<NavigationEntry> {
|
||||||
self.history.borrow_mut().pop(NavigationMode::GoingBack, cx)
|
self.history.pop(NavigationMode::GoingBack, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_forward(&self, cx: &mut WindowContext) -> Option<NavigationEntry> {
|
pub fn pop_forward(&mut self, cx: &mut WindowContext) -> Option<NavigationEntry> {
|
||||||
self.history
|
self.history.pop(NavigationMode::GoingForward, cx)
|
||||||
.borrow_mut()
|
|
||||||
.pop(NavigationMode::GoingForward, cx)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NavHistory {
|
impl NavHistory {
|
||||||
fn set_mode(&mut self, mode: NavigationMode) {
|
|
||||||
self.mode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn disable(&mut self) {
|
|
||||||
self.mode = NavigationMode::Disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enable(&mut self) {
|
|
||||||
self.mode = NavigationMode::Normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop(&mut self, mode: NavigationMode, cx: &mut WindowContext) -> Option<NavigationEntry> {
|
|
||||||
let entry = match mode {
|
|
||||||
NavigationMode::Normal | NavigationMode::Disabled | NavigationMode::ClosingItem => {
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
NavigationMode::GoingBack => &mut self.backward_stack,
|
|
||||||
NavigationMode::GoingForward => &mut self.forward_stack,
|
|
||||||
NavigationMode::ReopeningClosedItem => &mut self.closed_stack,
|
|
||||||
}
|
|
||||||
.pop_back();
|
|
||||||
if entry.is_some() {
|
|
||||||
self.did_update(cx);
|
|
||||||
}
|
|
||||||
entry
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push<D: 'static + Any>(
|
|
||||||
&mut self,
|
|
||||||
data: Option<D>,
|
|
||||||
item: Rc<dyn WeakItemHandle>,
|
|
||||||
cx: &mut WindowContext,
|
|
||||||
) {
|
|
||||||
match self.mode {
|
|
||||||
NavigationMode::Disabled => {}
|
|
||||||
NavigationMode::Normal | NavigationMode::ReopeningClosedItem => {
|
|
||||||
if self.backward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN {
|
|
||||||
self.backward_stack.pop_front();
|
|
||||||
}
|
|
||||||
self.backward_stack.push_back(NavigationEntry {
|
|
||||||
item,
|
|
||||||
data: data.map(|data| Box::new(data) as Box<dyn Any>),
|
|
||||||
timestamp: self.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
|
||||||
});
|
|
||||||
self.forward_stack.clear();
|
|
||||||
}
|
|
||||||
NavigationMode::GoingBack => {
|
|
||||||
if self.forward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN {
|
|
||||||
self.forward_stack.pop_front();
|
|
||||||
}
|
|
||||||
self.forward_stack.push_back(NavigationEntry {
|
|
||||||
item,
|
|
||||||
data: data.map(|data| Box::new(data) as Box<dyn Any>),
|
|
||||||
timestamp: self.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
NavigationMode::GoingForward => {
|
|
||||||
if self.backward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN {
|
|
||||||
self.backward_stack.pop_front();
|
|
||||||
}
|
|
||||||
self.backward_stack.push_back(NavigationEntry {
|
|
||||||
item,
|
|
||||||
data: data.map(|data| Box::new(data) as Box<dyn Any>),
|
|
||||||
timestamp: self.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
NavigationMode::ClosingItem => {
|
|
||||||
if self.closed_stack.len() >= MAX_NAVIGATION_HISTORY_LEN {
|
|
||||||
self.closed_stack.pop_front();
|
|
||||||
}
|
|
||||||
self.closed_stack.push_back(NavigationEntry {
|
|
||||||
item,
|
|
||||||
data: data.map(|data| Box::new(data) as Box<dyn Any>),
|
|
||||||
timestamp: self.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.did_update(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn did_update(&self, cx: &mut WindowContext) {
|
|
||||||
if let Some(pane) = self.pane.upgrade(cx) {
|
|
||||||
cx.defer(move |cx| {
|
|
||||||
pane.update(cx, |pane, cx| pane.history_updated(cx));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_item(&mut self, item_id: usize) {
|
|
||||||
self.paths_by_item.remove(&item_id);
|
|
||||||
self.backward_stack
|
|
||||||
.retain(|entry| entry.item.id() != item_id);
|
|
||||||
self.forward_stack
|
|
||||||
.retain(|entry| entry.item.id() != item_id);
|
|
||||||
self.closed_stack.retain(|entry| entry.item.id() != item_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PaneNavHistory {
|
|
||||||
pub fn for_each_entry(
|
pub fn for_each_entry(
|
||||||
&self,
|
&self,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
|
@ -1925,6 +1675,120 @@ impl PaneNavHistory {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_mode(&mut self, mode: NavigationMode) {
|
||||||
|
self.0.borrow_mut().mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mode(&self) -> NavigationMode {
|
||||||
|
self.0.borrow().mode
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disable(&mut self) {
|
||||||
|
self.0.borrow_mut().mode = NavigationMode::Disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable(&mut self) {
|
||||||
|
self.0.borrow_mut().mode = NavigationMode::Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self, mode: NavigationMode, cx: &mut WindowContext) -> Option<NavigationEntry> {
|
||||||
|
let mut state = self.0.borrow_mut();
|
||||||
|
let entry = match mode {
|
||||||
|
NavigationMode::Normal | NavigationMode::Disabled | NavigationMode::ClosingItem => {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
NavigationMode::GoingBack => &mut state.backward_stack,
|
||||||
|
NavigationMode::GoingForward => &mut state.forward_stack,
|
||||||
|
NavigationMode::ReopeningClosedItem => &mut state.closed_stack,
|
||||||
|
}
|
||||||
|
.pop_back();
|
||||||
|
if entry.is_some() {
|
||||||
|
self.did_update(cx);
|
||||||
|
}
|
||||||
|
entry
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push<D: 'static + Any>(
|
||||||
|
&mut self,
|
||||||
|
data: Option<D>,
|
||||||
|
item: Rc<dyn WeakItemHandle>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) {
|
||||||
|
let state = &mut *self.0.borrow_mut();
|
||||||
|
match state.mode {
|
||||||
|
NavigationMode::Disabled => {}
|
||||||
|
NavigationMode::Normal | NavigationMode::ReopeningClosedItem => {
|
||||||
|
if state.backward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN {
|
||||||
|
state.backward_stack.pop_front();
|
||||||
|
}
|
||||||
|
state.backward_stack.push_back(NavigationEntry {
|
||||||
|
item,
|
||||||
|
data: data.map(|data| Box::new(data) as Box<dyn Any>),
|
||||||
|
timestamp: state.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
||||||
|
});
|
||||||
|
state.forward_stack.clear();
|
||||||
|
}
|
||||||
|
NavigationMode::GoingBack => {
|
||||||
|
if state.forward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN {
|
||||||
|
state.forward_stack.pop_front();
|
||||||
|
}
|
||||||
|
state.forward_stack.push_back(NavigationEntry {
|
||||||
|
item,
|
||||||
|
data: data.map(|data| Box::new(data) as Box<dyn Any>),
|
||||||
|
timestamp: state.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
NavigationMode::GoingForward => {
|
||||||
|
if state.backward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN {
|
||||||
|
state.backward_stack.pop_front();
|
||||||
|
}
|
||||||
|
state.backward_stack.push_back(NavigationEntry {
|
||||||
|
item,
|
||||||
|
data: data.map(|data| Box::new(data) as Box<dyn Any>),
|
||||||
|
timestamp: state.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
NavigationMode::ClosingItem => {
|
||||||
|
if state.closed_stack.len() >= MAX_NAVIGATION_HISTORY_LEN {
|
||||||
|
state.closed_stack.pop_front();
|
||||||
|
}
|
||||||
|
state.closed_stack.push_back(NavigationEntry {
|
||||||
|
item,
|
||||||
|
data: data.map(|data| Box::new(data) as Box<dyn Any>),
|
||||||
|
timestamp: state.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.did_update(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn did_update(&self, cx: &mut WindowContext) {
|
||||||
|
let state = self.0.borrow();
|
||||||
|
if let Some(pane) = state.pane.upgrade(cx) {
|
||||||
|
cx.defer(move |cx| {
|
||||||
|
pane.update(cx, |pane, cx| pane.history_updated(cx));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_item(&mut self, item_id: usize) {
|
||||||
|
let mut state = self.0.borrow_mut();
|
||||||
|
state.paths_by_item.remove(&item_id);
|
||||||
|
state
|
||||||
|
.backward_stack
|
||||||
|
.retain(|entry| entry.item.id() != item_id);
|
||||||
|
state
|
||||||
|
.forward_stack
|
||||||
|
.retain(|entry| entry.item.id() != item_id);
|
||||||
|
state
|
||||||
|
.closed_stack
|
||||||
|
.retain(|entry| entry.item.id() != item_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_for_item(&self, item_id: usize) -> Option<(ProjectPath, Option<PathBuf>)> {
|
||||||
|
self.0.borrow().paths_by_item.get(&item_id).cloned()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PaneBackdrop<V: View> {
|
pub struct PaneBackdrop<V: View> {
|
||||||
|
|
|
@ -99,7 +99,7 @@ impl Item for SharedScreen {
|
||||||
Some(format!("{}'s screen", self.user.github_login).into())
|
Some(format!("{}'s screen", self.user.github_login).into())
|
||||||
}
|
}
|
||||||
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
|
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(nav_history) = self.nav_history.as_ref() {
|
if let Some(nav_history) = self.nav_history.as_mut() {
|
||||||
nav_history.push::<()>(None, cx);
|
nav_history.push::<()>(None, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,14 +153,13 @@ impl View for Toolbar {
|
||||||
let pane = pane.clone();
|
let pane = pane.clone();
|
||||||
cx.window_context().defer(move |cx| {
|
cx.window_context().defer(move |cx| {
|
||||||
workspace.update(cx, |workspace, cx| {
|
workspace.update(cx, |workspace, cx| {
|
||||||
Pane::go_back(workspace, Some(pane.clone()), cx)
|
workspace.go_back(pane.clone(), cx).detach_and_log_err(cx);
|
||||||
.detach_and_log_err(cx);
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
super::GoBack { pane: None },
|
super::GoBack,
|
||||||
"Go Back",
|
"Go Back",
|
||||||
cx,
|
cx,
|
||||||
));
|
));
|
||||||
|
@ -182,14 +181,15 @@ impl View for Toolbar {
|
||||||
let pane = pane.clone();
|
let pane = pane.clone();
|
||||||
cx.window_context().defer(move |cx| {
|
cx.window_context().defer(move |cx| {
|
||||||
workspace.update(cx, |workspace, cx| {
|
workspace.update(cx, |workspace, cx| {
|
||||||
Pane::go_forward(workspace, Some(pane.clone()), cx)
|
workspace
|
||||||
|
.go_forward(pane.clone(), cx)
|
||||||
.detach_and_log_err(cx);
|
.detach_and_log_err(cx);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
super::GoForward { pane: None },
|
super::GoForward,
|
||||||
"Go Forward",
|
"Go Forward",
|
||||||
cx,
|
cx,
|
||||||
));
|
));
|
||||||
|
|
|
@ -278,6 +278,19 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
|
||||||
workspace.toggle_dock(DockPosition::Bottom, action.focus, cx);
|
workspace.toggle_dock(DockPosition::Bottom, action.focus, cx);
|
||||||
});
|
});
|
||||||
cx.add_action(Workspace::activate_pane_at_index);
|
cx.add_action(Workspace::activate_pane_at_index);
|
||||||
|
cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| {
|
||||||
|
workspace.reopen_closed_item(cx).detach();
|
||||||
|
});
|
||||||
|
cx.add_action(|workspace: &mut Workspace, _: &GoBack, cx| {
|
||||||
|
workspace
|
||||||
|
.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
|
.detach();
|
||||||
|
});
|
||||||
|
cx.add_action(|workspace: &mut Workspace, _: &GoForward, cx| {
|
||||||
|
workspace
|
||||||
|
.go_forward(workspace.active_pane().downgrade(), cx)
|
||||||
|
.detach();
|
||||||
|
});
|
||||||
|
|
||||||
cx.add_action(|_: &mut Workspace, _: &install_cli::Install, cx| {
|
cx.add_action(|_: &mut Workspace, _: &install_cli::Install, cx| {
|
||||||
cx.spawn(|workspace, mut cx| async move {
|
cx.spawn(|workspace, mut cx| async move {
|
||||||
|
@ -1000,6 +1013,115 @@ impl Workspace {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn navigate_history(
|
||||||
|
&mut self,
|
||||||
|
pane: WeakViewHandle<Pane>,
|
||||||
|
mode: NavigationMode,
|
||||||
|
cx: &mut ViewContext<Workspace>,
|
||||||
|
) -> Task<Result<()>> {
|
||||||
|
let to_load = if let Some(pane) = pane.upgrade(cx) {
|
||||||
|
cx.focus(&pane);
|
||||||
|
|
||||||
|
pane.update(cx, |pane, cx| {
|
||||||
|
loop {
|
||||||
|
// Retrieve the weak item handle from the history.
|
||||||
|
let entry = pane.nav_history_mut().pop(mode, cx)?;
|
||||||
|
|
||||||
|
// If the item is still present in this pane, then activate it.
|
||||||
|
if let Some(index) = entry
|
||||||
|
.item
|
||||||
|
.upgrade(cx)
|
||||||
|
.and_then(|v| pane.index_for_item(v.as_ref()))
|
||||||
|
{
|
||||||
|
let prev_active_item_index = pane.active_item_index();
|
||||||
|
pane.nav_history_mut().set_mode(mode);
|
||||||
|
pane.activate_item(index, true, true, cx);
|
||||||
|
pane.nav_history_mut().set_mode(NavigationMode::Normal);
|
||||||
|
|
||||||
|
let mut navigated = prev_active_item_index != pane.active_item_index();
|
||||||
|
if let Some(data) = entry.data {
|
||||||
|
navigated |= pane.active_item()?.navigate(data, cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if navigated {
|
||||||
|
break None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the item is no longer present in this pane, then retrieve its
|
||||||
|
// project path in order to reopen it.
|
||||||
|
else {
|
||||||
|
break pane
|
||||||
|
.nav_history()
|
||||||
|
.path_for_item(entry.item.id())
|
||||||
|
.map(|(project_path, _)| (project_path, entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some((project_path, entry)) = to_load {
|
||||||
|
// If the item was no longer present, then load it again from its previous path.
|
||||||
|
let task = self.load_path(project_path, cx);
|
||||||
|
cx.spawn(|workspace, mut cx| async move {
|
||||||
|
let task = task.await;
|
||||||
|
let mut navigated = false;
|
||||||
|
if let Some((project_entry_id, build_item)) = task.log_err() {
|
||||||
|
let prev_active_item_id = pane.update(&mut cx, |pane, _| {
|
||||||
|
pane.nav_history_mut().set_mode(mode);
|
||||||
|
pane.active_item().map(|p| p.id())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
pane.update(&mut cx, |pane, cx| {
|
||||||
|
let item = pane.open_item(project_entry_id, true, cx, build_item);
|
||||||
|
navigated |= Some(item.id()) != prev_active_item_id;
|
||||||
|
pane.nav_history_mut().set_mode(NavigationMode::Normal);
|
||||||
|
if let Some(data) = entry.data {
|
||||||
|
navigated |= item.navigate(data, cx);
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !navigated {
|
||||||
|
workspace
|
||||||
|
.update(&mut cx, |workspace, cx| {
|
||||||
|
Self::navigate_history(workspace, pane, mode, cx)
|
||||||
|
})?
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Task::ready(Ok(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn go_back(
|
||||||
|
&mut self,
|
||||||
|
pane: WeakViewHandle<Pane>,
|
||||||
|
cx: &mut ViewContext<Workspace>,
|
||||||
|
) -> Task<Result<()>> {
|
||||||
|
self.navigate_history(pane, NavigationMode::GoingBack, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn go_forward(
|
||||||
|
&mut self,
|
||||||
|
pane: WeakViewHandle<Pane>,
|
||||||
|
cx: &mut ViewContext<Workspace>,
|
||||||
|
) -> Task<Result<()>> {
|
||||||
|
self.navigate_history(pane, NavigationMode::GoingForward, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reopen_closed_item(&mut self, cx: &mut ViewContext<Workspace>) -> Task<Result<()>> {
|
||||||
|
self.navigate_history(
|
||||||
|
self.active_pane().downgrade(),
|
||||||
|
NavigationMode::ReopeningClosedItem,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn client(&self) -> &Client {
|
pub fn client(&self) -> &Client {
|
||||||
&self.app_state.client
|
&self.app_state.client
|
||||||
}
|
}
|
||||||
|
@ -4037,9 +4159,7 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, cx| {
|
.update(cx, |workspace, cx| workspace.go_back(pane.downgrade(), cx))
|
||||||
Pane::go_back(workspace, Some(pane.downgrade()), cx)
|
|
||||||
})
|
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -120,8 +120,8 @@ pub fn menus() -> Vec<Menu<'static>> {
|
||||||
Menu {
|
Menu {
|
||||||
name: "Go",
|
name: "Go",
|
||||||
items: vec![
|
items: vec![
|
||||||
MenuItem::action("Back", workspace::GoBack { pane: None }),
|
MenuItem::action("Back", workspace::GoBack),
|
||||||
MenuItem::action("Forward", workspace::GoForward { pane: None }),
|
MenuItem::action("Forward", workspace::GoForward),
|
||||||
MenuItem::separator(),
|
MenuItem::separator(),
|
||||||
MenuItem::action("Go to File", file_finder::Toggle),
|
MenuItem::action("Go to File", file_finder::Toggle),
|
||||||
MenuItem::action("Go to Symbol in Project", project_symbols::Toggle),
|
MenuItem::action("Go to Symbol in Project", project_symbols::Toggle),
|
||||||
|
|
|
@ -663,7 +663,7 @@ mod tests {
|
||||||
use util::http::FakeHttpClient;
|
use util::http::FakeHttpClient;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
item::{Item, ItemHandle},
|
item::{Item, ItemHandle},
|
||||||
open_new, open_paths, pane, NewFile, Pane, SplitDirection, WorkspaceHandle,
|
open_new, open_paths, pane, NewFile, SplitDirection, WorkspaceHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
|
@ -1488,7 +1488,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_back(w, None, cx))
|
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1497,7 +1497,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_back(w, None, cx))
|
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1506,7 +1506,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_back(w, None, cx))
|
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1515,7 +1515,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_back(w, None, cx))
|
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1525,7 +1525,7 @@ mod tests {
|
||||||
|
|
||||||
// Go back one more time and ensure we don't navigate past the first item in the history.
|
// Go back one more time and ensure we don't navigate past the first item in the history.
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_back(w, None, cx))
|
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1534,7 +1534,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_forward(w, None, cx))
|
.update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1543,7 +1543,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_forward(w, None, cx))
|
.update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1561,7 +1561,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_forward(w, None, cx))
|
.update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1570,7 +1570,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_forward(w, None, cx))
|
.update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1579,7 +1579,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_back(w, None, cx))
|
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1601,7 +1601,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_back(w, None, cx))
|
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1609,7 +1609,7 @@ mod tests {
|
||||||
(file1.clone(), DisplayPoint::new(10, 0), 0.)
|
(file1.clone(), DisplayPoint::new(10, 0), 0.)
|
||||||
);
|
);
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_forward(w, None, cx))
|
.update(cx, |w, cx| w.go_forward(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1653,7 +1653,7 @@ mod tests {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_back(w, None, cx))
|
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1661,7 +1661,7 @@ mod tests {
|
||||||
(file1.clone(), DisplayPoint::new(2, 0), 0.)
|
(file1.clone(), DisplayPoint::new(2, 0), 0.)
|
||||||
);
|
);
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |w, cx| Pane::go_back(w, None, cx))
|
.update(cx, |w, cx| w.go_back(w.active_pane().downgrade(), cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1766,81 +1766,97 @@ mod tests {
|
||||||
// Reopen all the closed items, ensuring they are reopened in the same order
|
// Reopen all the closed items, ensuring they are reopened in the same order
|
||||||
// in which they were closed.
|
// in which they were closed.
|
||||||
workspace
|
workspace
|
||||||
.update(cx, Pane::reopen_closed_item)
|
.update(cx, Workspace::reopen_closed_item)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, Pane::reopen_closed_item)
|
.update(cx, Workspace::reopen_closed_item)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file2.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file2.clone()));
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, Pane::reopen_closed_item)
|
.update(cx, Workspace::reopen_closed_item)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, Pane::reopen_closed_item)
|
.update(cx, Workspace::reopen_closed_item)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
|
||||||
|
|
||||||
// Reopening past the last closed item is a no-op.
|
// Reopening past the last closed item is a no-op.
|
||||||
workspace
|
workspace
|
||||||
.update(cx, Pane::reopen_closed_item)
|
.update(cx, Workspace::reopen_closed_item)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
|
||||||
|
|
||||||
// Reopening closed items doesn't interfere with navigation history.
|
// Reopening closed items doesn't interfere with navigation history.
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, cx| Pane::go_back(workspace, None, cx))
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, cx| Pane::go_back(workspace, None, cx))
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file2.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file2.clone()));
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, cx| Pane::go_back(workspace, None, cx))
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, cx| Pane::go_back(workspace, None, cx))
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, cx| Pane::go_back(workspace, None, cx))
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, cx| Pane::go_back(workspace, None, cx))
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file2.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file2.clone()));
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, cx| Pane::go_back(workspace, None, cx))
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
|
||||||
|
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, cx| Pane::go_back(workspace, None, cx))
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.go_back(workspace.active_pane().downgrade(), cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
|
assert_eq!(active_path(&workspace, cx), Some(file1.clone()));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue