Detailed changes
@@ -2399,6 +2399,8 @@ impl Editor {
return;
}
+ self.push_to_navigation_history(cx);
+
let selection = Selection {
id: post_inc(&mut self.next_selection_id),
start: 0,
@@ -2421,6 +2423,8 @@ impl Editor {
return;
}
+ self.push_to_navigation_history(cx);
+
let cursor = self.buffer.read(cx).read(cx).len();
let selection = Selection {
id: post_inc(&mut self.next_selection_id),
@@ -2432,6 +2436,15 @@ impl Editor {
self.update_selections(vec![selection], Some(Autoscroll::Fit), cx);
}
+ fn push_to_navigation_history(&self, cx: &mut ViewContext<Self>) {
+ if let Some(navigation) = &self.navigation {
+ if let Some(last_selection) = self.selections.iter().max_by_key(|s| s.id) {
+ let cursor = last_selection.head();
+ navigation.push(Some(cursor), cx);
+ }
+ }
+ }
+
pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
let mut selection = self.local_selections::<usize>(cx).first().unwrap().clone();
selection.set_head(self.buffer.read(cx).read(cx).len());
@@ -1,5 +1,4 @@
-use crate::{Autoscroll, Editor, Event};
-use crate::{MultiBuffer, ToPoint as _};
+use crate::{Anchor, Autoscroll, Editor, Event, MultiBuffer, ToOffset, ToPoint as _};
use anyhow::Result;
use gpui::{
elements::*, AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, RenderContext,
@@ -106,6 +105,13 @@ impl ItemView for Editor {
BufferItemHandle(self.buffer.read(cx).as_singleton().unwrap())
}
+ fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) {
+ if let Some(anchor) = data.downcast_ref::<Anchor>() {
+ let offset = anchor.to_offset(&self.buffer.read(cx).read(cx));
+ self.select_ranges([offset..offset], Some(Autoscroll::Fit), cx);
+ }
+ }
+
fn title(&self, cx: &AppContext) -> String {
let filename = self
.buffer()
@@ -134,9 +140,7 @@ impl ItemView for Editor {
}
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
- if let Some(navigation) = self.navigation.as_ref() {
- navigation.push::<(), _>(None, cx);
- }
+ self.push_to_navigation_history(cx);
}
fn is_dirty(&self, cx: &AppContext) -> bool {
@@ -84,6 +84,7 @@ struct NavigationHistory {
paths_by_item: HashMap<usize, ProjectPath>,
}
+#[derive(Copy, Clone)]
enum NavigationHistoryMode {
Normal,
GoingBack,
@@ -116,77 +117,81 @@ impl Pane {
}
pub fn go_back(workspace: &mut Workspace, _: &GoBack, cx: &mut ViewContext<Workspace>) {
- 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;
- }
-
- 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();
- }
+ Self::navigate_history(workspace, NavigationHistoryMode::GoingBack, cx);
}
- pub fn go_forward(&mut self, _: &GoForward, cx: &mut ViewContext<Self>) {
- if self.navigation.0.borrow().forward_stack.is_empty() {
- return;
- }
+ pub fn go_forward(workspace: &mut Workspace, _: &GoForward, cx: &mut ViewContext<Workspace>) {
+ Self::navigate_history(workspace, NavigationHistoryMode::GoingForward, cx);
+ }
- if let Some(item_view) = self.active_item() {
- self.navigation.0.borrow_mut().mode = NavigationHistoryMode::GoingForward;
- item_view.deactivated(cx);
- self.navigation.0.borrow_mut().mode = NavigationHistoryMode::Normal;
- }
+ fn navigate_history(
+ workspace: &mut Workspace,
+ mode: NavigationHistoryMode,
+ cx: &mut ViewContext<Workspace>,
+ ) -> Option<()> {
+ let (project_path, entry) = workspace.active_pane().update(cx, |pane, cx| {
+ // Retrieve the weak item handle from the history.
+ let entry = pane.navigation.pop(mode)?;
- let mut navigation = self.navigation.0.borrow_mut();
- if let Some(entry) = navigation.forward_stack.pop() {
+ // If the item is still present in this pane, then activate it.
if let Some(index) = entry
.item_view
.upgrade(cx)
- .and_then(|v| self.index_for_item_view(v.as_ref()))
+ .and_then(|v| pane.index_for_item_view(v.as_ref()))
{
- self.active_item_index = index;
- drop(navigation);
- self.focus_active_item(cx);
+ if let Some(item_view) = pane.active_item() {
+ pane.navigation.set_mode(mode);
+ item_view.deactivated(cx);
+ pane.navigation.set_mode(NavigationHistoryMode::Normal);
+ }
+
+ pane.active_item_index = index;
+ pane.focus_active_item(cx);
+ if let Some(data) = entry.data {
+ pane.active_item()?.navigate(data, cx);
+ }
cx.notify();
+ None
}
- }
+ // If the item is no longer present in this pane, then retrieve its
+ // project path in order to reopen it.
+ else {
+ pane.navigation
+ .0
+ .borrow_mut()
+ .paths_by_item
+ .get(&entry.item_view.id())
+ .cloned()
+ .map(|project_path| (project_path, entry))
+ }
+ })?;
+
+ // 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 item = task.await?;
+ workspace.update(&mut cx, |workspace, cx| {
+ let pane = workspace.active_pane().clone();
+ pane.update(cx, |pane, cx| {
+ pane.navigation.set_mode(mode);
+ let item_view = pane.open_item(item, workspace, cx);
+ pane.navigation.set_mode(NavigationHistoryMode::Normal);
+
+ if let Some(data) = entry.data {
+ item_view.navigate(data, cx);
+ }
+
+ cx.notify();
+ });
+ });
+ Ok(())
+ }
+ .log_err()
+ })
+ .detach();
+
+ None
}
pub fn open_item<T>(
@@ -511,6 +516,18 @@ impl View for Pane {
}
impl Navigation {
+ fn pop(&self, mode: NavigationHistoryMode) -> Option<NavigationEntry> {
+ match mode {
+ NavigationHistoryMode::Normal => None,
+ NavigationHistoryMode::GoingBack => self.0.borrow_mut().backward_stack.pop(),
+ NavigationHistoryMode::GoingForward => self.0.borrow_mut().forward_stack.pop(),
+ }
+ }
+
+ fn set_mode(&self, mode: NavigationHistoryMode) {
+ self.0.borrow_mut().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 {
@@ -33,6 +33,7 @@ use sidebar::{Side, Sidebar, SidebarItemId, ToggleSidebarItem, ToggleSidebarItem
use status_bar::StatusBar;
pub use status_bar::StatusItemView;
use std::{
+ any::Any,
future::Future,
hash::{Hash, Hasher},
path::{Path, PathBuf},
@@ -148,6 +149,7 @@ pub trait ItemView: View {
fn added_to_pane(&mut self, _: Rc<Navigation>, _: &mut ViewContext<Self>) {}
fn deactivated(&mut self, _: &mut ViewContext<Self>) {}
+ fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) {}
fn item_handle(&self, cx: &AppContext) -> Self::ItemHandle;
fn title(&self, cx: &AppContext) -> String;
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
@@ -211,6 +213,7 @@ pub trait ItemViewHandle {
fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option<Box<dyn ItemViewHandle>>;
fn added_to_pane(&mut self, cx: &mut ViewContext<Pane>);
fn deactivated(&self, cx: &mut MutableAppContext);
+ fn navigate(&self, data: Box<dyn Any>, cx: &mut MutableAppContext);
fn id(&self) -> usize;
fn to_any(&self) -> AnyViewHandle;
fn is_dirty(&self, cx: &AppContext) -> bool;
@@ -368,6 +371,10 @@ impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
self.update(cx, |this, cx| this.deactivated(cx));
}
+ fn navigate(&self, data: Box<dyn Any>, cx: &mut MutableAppContext) {
+ self.update(cx, |this, cx| this.navigate(data, cx));
+ }
+
fn save(&self, cx: &mut MutableAppContext) -> Result<Task<Result<()>>> {
self.update(cx, |item, cx| item.save(cx))
}