This commit is contained in:
Antonio Scandurra 2022-01-20 18:11:37 +01:00
parent fad5c98b8d
commit c450945001
5 changed files with 95 additions and 65 deletions

View File

@ -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)

View File

@ -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!(

View File

@ -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
}))
}

View File

@ -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>>,
}
pub struct ItemNavHistory {
history: Rc<RefCell<NavHistory>>,
item_view: Rc<dyn WeakItemViewHandle>,
}
#[derive(Default)]
pub struct NavHistory(RefCell<NavHistoryState>);
#[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>),
});
}

View File

@ -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)