diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index cff31fc6fbf84799f02bab5dd4b8d91892c64e3c..00e60f5c4f58eca1bd0a7373e5d82940d9d81d82 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -15,9 +15,9 @@ use gpui::{ use language::{Bias, Buffer, Diagnostic, DiagnosticEntry, Point, Selection, SelectionGoal}; use postage::watch; use project::{Project, ProjectPath}; -use std::{any::TypeId, cmp::Ordering, mem, ops::Range, path::PathBuf, rc::Rc, sync::Arc}; +use std::{any::TypeId, cmp::Ordering, mem, ops::Range, path::PathBuf, sync::Arc}; use util::TryFutureExt; -use workspace::{NavHistory, Workspace}; +use workspace::{ItemNavHistory, Workspace}; action!(Deploy); action!(OpenExcerpts); @@ -517,7 +517,7 @@ impl workspace::Item for ProjectDiagnostics { fn build_view( handle: ModelHandle, workspace: &Workspace, - _: Rc, + _: ItemNavHistory, cx: &mut ViewContext, ) -> Self::View { ProjectDiagnosticsEditor::new(handle, workspace.weak_handle(), workspace.settings(), cx) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 42b2fe30a19e2f04cc74611084e5410f4accd9c4..daca2d2ca7c0a857170e7dbff4e593b2eedef72e 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -41,7 +41,6 @@ use std::{ iter::{self, FromIterator}, mem, ops::{Deref, Range, RangeInclusive, Sub}, - rc::Rc, sync::Arc, time::{Duration, Instant}, }; @@ -49,7 +48,7 @@ use sum_tree::Bias; use text::rope::TextDimension; use theme::{DiagnosticStyle, EditorStyle}; use util::post_inc; -use workspace::{NavHistory, PathOpener, Workspace}; +use workspace::{ItemNavHistory, PathOpener, Workspace}; const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); const MAX_LINE_LEN: usize = 1024; @@ -382,7 +381,7 @@ pub struct Editor { mode: EditorMode, placeholder_text: Option>, highlighted_rows: Option>, - nav_history: Option>, + nav_history: Option, } pub struct EditorSnapshot { @@ -468,7 +467,10 @@ impl Editor { let mut clone = Self::new(self.buffer.clone(), self.build_settings.clone(), cx); clone.scroll_position = self.scroll_position; clone.scroll_top_anchor = self.scroll_top_anchor.clone(); - clone.nav_history = self.nav_history.clone(); + clone.nav_history = self + .nav_history + .as_ref() + .map(|nav_history| nav_history.clone(&cx.handle())); clone } @@ -2476,13 +2478,10 @@ impl Editor { } } - nav_history.push( - Some(NavigationData { - anchor: position, - offset, - }), - cx, - ); + nav_history.push(Some(NavigationData { + anchor: position, + offset, + })); } } @@ -4041,7 +4040,7 @@ pub fn settings_builder( mod tests { use super::*; use language::LanguageConfig; - use std::time::Instant; + use std::{cell::RefCell, rc::Rc, time::Instant}; use text::Point; use unindent::Unindent; use util::test::sample_text; @@ -4220,22 +4219,22 @@ mod tests { fn test_navigation_history(cx: &mut gpui::MutableAppContext) { cx.add_window(Default::default(), |cx| { use workspace::ItemView; - let nav_history = Rc::new(workspace::NavHistory::default()); + let nav_history = Rc::new(RefCell::new(workspace::NavHistory::default())); let settings = EditorSettings::test(&cx); let buffer = MultiBuffer::build_simple(&sample_text(30, 5, 'a'), cx); let mut editor = build_editor(buffer.clone(), settings, cx); - editor.nav_history = Some(nav_history.clone()); + editor.nav_history = Some(ItemNavHistory::new(nav_history.clone(), &cx.handle())); // Move the cursor a small distance. // Nothing is added to the navigation history. editor.select_display_ranges(&[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)], cx); editor.select_display_ranges(&[DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)], cx); - assert!(nav_history.pop_backward().is_none()); + assert!(nav_history.borrow_mut().pop_backward().is_none()); // Move the cursor a large distance. // The history can jump back to the previous position. editor.select_display_ranges(&[DisplayPoint::new(13, 0)..DisplayPoint::new(13, 3)], cx); - let nav_entry = nav_history.pop_backward().unwrap(); + let nav_entry = nav_history.borrow_mut().pop_backward().unwrap(); editor.navigate(nav_entry.data.unwrap(), cx); assert_eq!(nav_entry.item_view.id(), cx.view_id()); assert_eq!( @@ -4251,7 +4250,7 @@ mod tests { editor.selected_display_ranges(cx), &[DisplayPoint::new(5, 0)..DisplayPoint::new(5, 0)] ); - assert!(nav_history.pop_backward().is_none()); + assert!(nav_history.borrow_mut().pop_backward().is_none()); // Move the cursor a large distance via the mouse. // The history can jump back to the previous position. @@ -4261,7 +4260,7 @@ mod tests { editor.selected_display_ranges(cx), &[DisplayPoint::new(15, 0)..DisplayPoint::new(15, 0)] ); - let nav_entry = nav_history.pop_backward().unwrap(); + let nav_entry = nav_history.borrow_mut().pop_backward().unwrap(); editor.navigate(nav_entry.data.unwrap(), cx); assert_eq!(nav_entry.item_view.id(), cx.view_id()); assert_eq!( diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index dd471a8c36dacdda4541240b6331c9a4ccdde6f0..07caad356263556526b08f31c2437ca8ce8b22f3 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -8,13 +8,14 @@ use language::{Bias, Buffer, Diagnostic}; use postage::watch; use project::worktree::File; use project::{Project, ProjectEntry, ProjectPath}; +use std::cell::RefCell; use std::rc::Rc; use std::{fmt::Write, path::PathBuf}; use text::{Point, Selection}; use util::TryFutureExt; use workspace::{ - ItemHandle, ItemView, ItemViewHandle, NavHistory, PathOpener, Settings, StatusItemView, - WeakItemHandle, Workspace, + ItemHandle, ItemNavHistory, ItemView, ItemViewHandle, NavHistory, PathOpener, Settings, + StatusItemView, WeakItemHandle, Workspace, }; pub struct BufferOpener; @@ -46,7 +47,7 @@ impl ItemHandle for BufferItemHandle { &self, window_id: usize, workspace: &Workspace, - nav_history: Rc, + nav_history: Rc>, cx: &mut MutableAppContext, ) -> Box { let buffer = cx.add_model(|cx| MultiBuffer::singleton(self.0.clone(), cx)); @@ -57,7 +58,7 @@ impl ItemHandle for BufferItemHandle { crate::settings_builder(weak_buffer, workspace.settings()), cx, ); - editor.nav_history = Some(nav_history); + editor.nav_history = Some(ItemNavHistory::new(nav_history, &cx.handle())); editor })) } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 524ccf68e21ee551aa0f3395bba64e8230bf23e7..6b099b492d958be5674cbdb44e5f17393420c946 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -76,14 +76,16 @@ pub struct Pane { item_views: Vec<(usize, Box)>, active_item_index: usize, settings: watch::Receiver, - nav_history: Rc, + nav_history: Rc>, } -#[derive(Default)] -pub struct NavHistory(RefCell); +pub struct ItemNavHistory { + history: Rc>, + item_view: Rc, +} #[derive(Default)] -struct NavHistoryState { +pub struct NavHistory { mode: NavigationMode, backward_stack: VecDeque, forward_stack: VecDeque, @@ -104,7 +106,7 @@ impl Default for NavigationMode { } pub struct NavigationEntry { - pub item_view: Box, + pub item_view: Rc, pub data: Option>, } @@ -148,7 +150,7 @@ impl Pane { ) -> Task<()> { let to_load = pane.update(cx, |pane, cx| { // Retrieve the weak item handle from the history. - let nav_entry = pane.nav_history.pop(mode)?; + let nav_entry = pane.nav_history.borrow_mut().pop(mode)?; // If the item is still present in this pane, then activate it. if let Some(index) = nav_entry @@ -157,9 +159,11 @@ impl Pane { .and_then(|v| pane.index_for_item_view(v.as_ref())) { if let Some(item_view) = pane.active_item() { - pane.nav_history.set_mode(mode); + pane.nav_history.borrow_mut().set_mode(mode); item_view.deactivated(cx); - pane.nav_history.set_mode(NavigationMode::Normal); + pane.nav_history + .borrow_mut() + .set_mode(NavigationMode::Normal); } pane.active_item_index = index; @@ -174,7 +178,6 @@ impl Pane { // project path in order to reopen it. else { pane.nav_history - .0 .borrow_mut() .project_entries_by_item .get(&nav_entry.item_view.id()) @@ -192,9 +195,11 @@ impl Pane { if let Some(pane) = cx.read(|cx| pane.upgrade(cx)) { if let Some(item) = item.log_err() { workspace.update(&mut cx, |workspace, cx| { - pane.update(cx, |p, _| p.nav_history.set_mode(mode)); + pane.update(cx, |p, _| p.nav_history.borrow_mut().set_mode(mode)); let item_view = workspace.open_item_in_pane(item, &pane, cx); - pane.update(cx, |p, _| p.nav_history.set_mode(NavigationMode::Normal)); + pane.update(cx, |p, _| { + p.nav_history.borrow_mut().set_mode(NavigationMode::Normal) + }); if let Some(data) = nav_entry.data { item_view.navigate(data, cx); @@ -322,7 +327,7 @@ impl Pane { item_view.deactivated(cx); } - let mut nav_history = self.nav_history.0.borrow_mut(); + let mut nav_history = self.nav_history.borrow_mut(); if let Some(entry) = item_view.project_entry(cx) { nav_history .project_entries_by_item @@ -538,16 +543,36 @@ impl View for Pane { } } +impl ItemNavHistory { + pub fn new(history: Rc>, item_view: &ViewHandle) -> Self { + Self { + history, + item_view: Rc::new(item_view.downgrade()), + } + } + + pub fn clone(&self, item_view: &ViewHandle) -> Self { + Self { + history: self.history.clone(), + item_view: Rc::new(item_view.downgrade()), + } + } + + pub fn push(&self, data: Option) { + self.history.borrow_mut().push(data, self.item_view.clone()); + } +} + impl NavHistory { - pub fn pop_backward(&self) -> Option { - self.0.borrow_mut().backward_stack.pop_back() + pub fn pop_backward(&mut self) -> Option { + self.backward_stack.pop_back() } - pub fn pop_forward(&self) -> Option { - self.0.borrow_mut().forward_stack.pop_back() + pub fn pop_forward(&mut self) -> Option { + self.forward_stack.pop_back() } - fn pop(&self, mode: NavigationMode) -> Option { + fn pop(&mut self, mode: NavigationMode) -> Option { match mode { NavigationMode::Normal => None, NavigationMode::GoingBack => self.pop_backward(), @@ -555,38 +580,41 @@ impl NavHistory { } } - fn set_mode(&self, mode: NavigationMode) { - self.0.borrow_mut().mode = mode; + fn set_mode(&mut self, mode: NavigationMode) { + self.mode = mode; } - pub fn push(&self, data: Option, cx: &mut ViewContext) { - let mut state = self.0.borrow_mut(); - match state.mode { + pub fn push( + &mut self, + data: Option, + item_view: Rc, + ) { + match self.mode { NavigationMode::Normal => { - if state.backward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN { - state.backward_stack.pop_front(); + if self.backward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN { + self.backward_stack.pop_front(); } - state.backward_stack.push_back(NavigationEntry { - item_view: Box::new(cx.weak_handle()), + self.backward_stack.push_back(NavigationEntry { + item_view, data: data.map(|data| Box::new(data) as Box), }); - state.forward_stack.clear(); + self.forward_stack.clear(); } NavigationMode::GoingBack => { - if state.forward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN { - state.forward_stack.pop_front(); + if self.forward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN { + self.forward_stack.pop_front(); } - state.forward_stack.push_back(NavigationEntry { - item_view: Box::new(cx.weak_handle()), + self.forward_stack.push_back(NavigationEntry { + item_view, data: data.map(|data| Box::new(data) as Box), }); } NavigationMode::GoingForward => { - if state.backward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN { - state.backward_stack.pop_front(); + if self.backward_stack.len() >= MAX_NAVIGATION_HISTORY_LEN { + self.backward_stack.pop_front(); } - state.backward_stack.push_back(NavigationEntry { - item_view: Box::new(cx.weak_handle()), + self.backward_stack.push_back(NavigationEntry { + item_view, data: data.map(|data| Box::new(data) as Box), }); } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 2f661789a3dab3f8157d02a724ea330c74923974..51709749a66130fbce98617c5f35fa68111e2917 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -34,6 +34,7 @@ use status_bar::StatusBar; pub use status_bar::StatusItemView; use std::{ any::{Any, TypeId}, + cell::RefCell, future::Future, hash::{Hash, Hasher}, path::{Path, PathBuf}, @@ -141,7 +142,7 @@ pub trait Item: Entity + Sized { fn build_view( handle: ModelHandle, workspace: &Workspace, - nav_history: Rc, + nav_history: ItemNavHistory, cx: &mut ViewContext, ) -> Self::View; fn project_entry(&self) -> Option; @@ -205,7 +206,7 @@ pub trait ItemHandle: Send + Sync { &self, window_id: usize, workspace: &Workspace, - nav_history: Rc, + nav_history: Rc>, cx: &mut MutableAppContext, ) -> Box; fn boxed_clone(&self) -> Box; @@ -258,10 +259,11 @@ impl ItemHandle for ModelHandle { &self, window_id: usize, workspace: &Workspace, - nav_history: Rc, + nav_history: Rc>, cx: &mut MutableAppContext, ) -> Box { Box::new(cx.add_view(window_id, |cx| { + let nav_history = ItemNavHistory::new(nav_history, &cx.handle()); T::build_view(self.clone(), workspace, nav_history, cx) })) } @@ -292,7 +294,7 @@ impl ItemHandle for Box { &self, window_id: usize, workspace: &Workspace, - nav_history: Rc, + nav_history: Rc>, cx: &mut MutableAppContext, ) -> Box { ItemHandle::add_view(self.as_ref(), window_id, workspace, nav_history, cx)