WIP

Antonio Scandurra created

Change summary

crates/diagnostics/src/diagnostics.rs |  6 
crates/editor/src/editor.rs           | 35 +++++-----
crates/editor/src/items.rs            |  9 +-
crates/workspace/src/pane.rs          | 98 ++++++++++++++++++----------
crates/workspace/src/workspace.rs     | 10 +-
5 files changed, 94 insertions(+), 64 deletions(-)

Detailed changes

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<Self>,
         workspace: &Workspace,
-        _: Rc<NavHistory>,
+        _: ItemNavHistory,
         cx: &mut ViewContext<Self::View>,
     ) -> Self::View {
         ProjectDiagnosticsEditor::new(handle, workspace.weak_handle(), workspace.settings(), cx)

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<Arc<str>>,
     highlighted_rows: Option<Range<u32>>,
-    nav_history: Option<Rc<NavHistory>>,
+    nav_history: Option<ItemNavHistory>,
 }
 
 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!(

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<NavHistory>,
+        nav_history: Rc<RefCell<NavHistory>>,
         cx: &mut MutableAppContext,
     ) -> Box<dyn ItemViewHandle> {
         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
         }))
     }

crates/workspace/src/pane.rs 🔗

@@ -76,14 +76,16 @@ pub struct Pane {
     item_views: Vec<(usize, Box<dyn ItemViewHandle>)>,
     active_item_index: usize,
     settings: watch::Receiver<Settings>,
-    nav_history: Rc<NavHistory>,
+    nav_history: Rc<RefCell<NavHistory>>,
 }
 
-#[derive(Default)]
-pub struct NavHistory(RefCell<NavHistoryState>);
+pub struct ItemNavHistory {
+    history: Rc<RefCell<NavHistory>>,
+    item_view: Rc<dyn WeakItemViewHandle>,
+}
 
 #[derive(Default)]
-struct NavHistoryState {
+pub struct NavHistory {
     mode: NavigationMode,
     backward_stack: VecDeque<NavigationEntry>,
     forward_stack: VecDeque<NavigationEntry>,
@@ -104,7 +106,7 @@ impl Default for NavigationMode {
 }
 
 pub struct NavigationEntry {
-    pub item_view: Box<dyn WeakItemViewHandle>,
+    pub item_view: Rc<dyn WeakItemViewHandle>,
     pub data: Option<Box<dyn Any>>,
 }
 
@@ -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<T: ItemView>(history: Rc<RefCell<NavHistory>>, item_view: &ViewHandle<T>) -> Self {
+        Self {
+            history,
+            item_view: Rc::new(item_view.downgrade()),
+        }
+    }
+
+    pub fn clone<T: ItemView>(&self, item_view: &ViewHandle<T>) -> Self {
+        Self {
+            history: self.history.clone(),
+            item_view: Rc::new(item_view.downgrade()),
+        }
+    }
+
+    pub fn push<D: 'static + Any>(&self, data: Option<D>) {
+        self.history.borrow_mut().push(data, self.item_view.clone());
+    }
+}
+
 impl NavHistory {
-    pub fn pop_backward(&self) -> Option<NavigationEntry> {
-        self.0.borrow_mut().backward_stack.pop_back()
+    pub fn pop_backward(&mut self) -> Option<NavigationEntry> {
+        self.backward_stack.pop_back()
     }
 
-    pub fn pop_forward(&self) -> Option<NavigationEntry> {
-        self.0.borrow_mut().forward_stack.pop_back()
+    pub fn pop_forward(&mut self) -> Option<NavigationEntry> {
+        self.forward_stack.pop_back()
     }
 
-    fn pop(&self, mode: NavigationMode) -> Option<NavigationEntry> {
+    fn pop(&mut self, mode: NavigationMode) -> Option<NavigationEntry> {
         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<D: 'static + Any, T: ItemView>(&self, data: Option<D>, cx: &mut ViewContext<T>) {
-        let mut state = self.0.borrow_mut();
-        match state.mode {
+    pub fn push<D: 'static + Any>(
+        &mut self,
+        data: Option<D>,
+        item_view: Rc<dyn WeakItemViewHandle>,
+    ) {
+        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<dyn Any>),
                 });
-                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<dyn Any>),
                 });
             }
             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<dyn Any>),
                 });
             }

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<Self>,
         workspace: &Workspace,
-        nav_history: Rc<NavHistory>,
+        nav_history: ItemNavHistory,
         cx: &mut ViewContext<Self::View>,
     ) -> Self::View;
     fn project_entry(&self) -> Option<ProjectEntry>;
@@ -205,7 +206,7 @@ pub trait ItemHandle: Send + Sync {
         &self,
         window_id: usize,
         workspace: &Workspace,
-        nav_history: Rc<NavHistory>,
+        nav_history: Rc<RefCell<NavHistory>>,
         cx: &mut MutableAppContext,
     ) -> Box<dyn ItemViewHandle>;
     fn boxed_clone(&self) -> Box<dyn ItemHandle>;
@@ -258,10 +259,11 @@ impl<T: Item> ItemHandle for ModelHandle<T> {
         &self,
         window_id: usize,
         workspace: &Workspace,
-        nav_history: Rc<NavHistory>,
+        nav_history: Rc<RefCell<NavHistory>>,
         cx: &mut MutableAppContext,
     ) -> Box<dyn ItemViewHandle> {
         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<dyn ItemHandle> {
         &self,
         window_id: usize,
         workspace: &Workspace,
-        nav_history: Rc<NavHistory>,
+        nav_history: Rc<RefCell<NavHistory>>,
         cx: &mut MutableAppContext,
     ) -> Box<dyn ItemViewHandle> {
         ItemHandle::add_view(self.as_ref(), window_id, workspace, nav_history, cx)