Compare commits
1 Commits
main
...
tag-stack-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b69a2ea200 |
@@ -67,6 +67,7 @@
|
||||
"ctrl-o": "pane::GoBack",
|
||||
"ctrl-i": "pane::GoForward",
|
||||
"ctrl-]": "editor::GoToDefinition",
|
||||
"ctrl-t": "pane::GoToOlderTag",
|
||||
"escape": "vim::SwitchToNormalMode",
|
||||
"ctrl-[": "vim::SwitchToNormalMode",
|
||||
"v": "vim::ToggleVisual",
|
||||
|
||||
@@ -25,6 +25,7 @@ use std::{
|
||||
any::{Any, TypeId},
|
||||
collections::hash_map::Entry,
|
||||
ops::Range,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
use ui::{CommonAnimationExt, IconButtonShape, KeyBinding, Tooltip, prelude::*, vertical_divider};
|
||||
@@ -516,12 +517,7 @@ impl Item for AgentDiffPane {
|
||||
.update(cx, |editor, cx| editor.deactivated(window, cx));
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
fn navigate(&mut self, data: Rc<dyn Any>, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -2530,7 +2530,7 @@ impl Item for TextThreadEditor {
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn std::any::Any>,
|
||||
data: Rc<dyn std::any::Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
|
||||
@@ -18,6 +18,7 @@ use project::Project;
|
||||
use rpc::proto::ChannelVisibility;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
use ui::prelude::*;
|
||||
@@ -515,12 +516,7 @@ impl Item for ChannelView {
|
||||
})))
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
fn navigate(&mut self, data: Rc<dyn Any>, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use std::any::{Any, TypeId};
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use collections::HashMap;
|
||||
use dap::StackFrameId;
|
||||
@@ -331,12 +334,7 @@ impl Item for StackTraceView {
|
||||
.update(cx, |editor, cx| editor.deactivated(window, cx));
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
fn navigate(&mut self, data: Rc<dyn Any>, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ use settings::Settings;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
cmp::Ordering,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
use text::{Anchor, BufferSnapshot, OffsetRangeExt};
|
||||
@@ -734,12 +735,7 @@ impl Item for BufferDiagnosticsEditor {
|
||||
self.multibuffer.read(cx).is_dirty(cx)
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
fn navigate(&mut self, data: Rc<dyn Any>, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ use std::{
|
||||
any::{Any, TypeId},
|
||||
cmp,
|
||||
ops::{Range, RangeInclusive},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
@@ -728,12 +729,7 @@ impl Item for ProjectDiagnosticsEditor {
|
||||
.update(cx, |editor, cx| editor.deactivated(window, cx));
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
fn navigate(&mut self, data: Rc<dyn Any>, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -14038,6 +14038,27 @@ impl Editor {
|
||||
);
|
||||
}
|
||||
|
||||
fn finish_tag_jump(&mut self, point: Point, cx: &mut Context<Self>) {
|
||||
let Some(nav_history) = self.nav_history.as_mut() else {
|
||||
return;
|
||||
};
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let cursor_anchor = snapshot.anchor_after(point);
|
||||
let cursor_position = cursor_anchor.to_point(&snapshot);
|
||||
let scroll_state = self.scroll_manager.anchor();
|
||||
let scroll_top_row = scroll_state.top_row(&snapshot);
|
||||
dbg!("finish tag jump", cursor_position);
|
||||
nav_history.finish_tag_jump(
|
||||
Some(NavigationData {
|
||||
cursor_anchor,
|
||||
cursor_position,
|
||||
scroll_anchor: scroll_state,
|
||||
scroll_top_row,
|
||||
}),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
fn push_to_nav_history(
|
||||
&mut self,
|
||||
cursor_anchor: Anchor,
|
||||
@@ -16437,18 +16458,37 @@ impl Editor {
|
||||
let Some(provider) = self.semantics_provider.clone() else {
|
||||
return Task::ready(Ok(Navigated::No));
|
||||
};
|
||||
let head = self
|
||||
let cursor = self
|
||||
.selections
|
||||
.newest::<usize>(&self.display_snapshot(cx))
|
||||
.head();
|
||||
let buffer = self.buffer.read(cx);
|
||||
let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
|
||||
let multi_buffer = self.buffer.read(cx);
|
||||
let Some((buffer, head)) = multi_buffer.text_anchor_for_position(cursor, cx) else {
|
||||
return Task::ready(Ok(Navigated::No));
|
||||
};
|
||||
let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
|
||||
return Task::ready(Ok(Navigated::No));
|
||||
};
|
||||
|
||||
if let Some(nav_history) = self.nav_history.as_mut() {
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let cursor_anchor = snapshot.anchor_after(cursor);
|
||||
let cursor_position = snapshot.offset_to_point(cursor);
|
||||
let scroll_anchor = self.scroll_manager.anchor();
|
||||
let scroll_top_row = scroll_anchor.top_row(&snapshot);
|
||||
|
||||
dbg!("start tag jump", cursor_position);
|
||||
nav_history.start_tag_jump(
|
||||
Some(NavigationData {
|
||||
cursor_anchor,
|
||||
cursor_position,
|
||||
scroll_anchor,
|
||||
scroll_top_row,
|
||||
}),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
cx.spawn_in(window, async move |editor, cx| {
|
||||
let Some(definitions) = definitions.await? else {
|
||||
return Ok(Navigated::No);
|
||||
@@ -16693,6 +16733,7 @@ impl Editor {
|
||||
if !split
|
||||
&& Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
|
||||
{
|
||||
editor.finish_tag_jump(range.start, cx);
|
||||
editor.go_to_singleton_buffer_range(range, window, cx);
|
||||
} else {
|
||||
let pane = workspace.read(cx).active_pane().clone();
|
||||
@@ -16718,6 +16759,7 @@ impl Editor {
|
||||
// When selecting a definition in a different buffer, disable the nav history
|
||||
// to avoid creating a history entry at the previous cursor location.
|
||||
pane.update(cx, |pane, _| pane.disable_history());
|
||||
target_editor.finish_tag_jump(range.start, cx);
|
||||
target_editor.go_to_singleton_buffer_range(range, window, cx);
|
||||
pane.update(cx, |pane, _| pane.enable_history());
|
||||
});
|
||||
@@ -17039,6 +17081,7 @@ impl Editor {
|
||||
|
||||
multibuffer.with_title(title)
|
||||
});
|
||||
let first_range = ranges.first().cloned();
|
||||
let existing = workspace.active_pane().update(cx, |pane, cx| {
|
||||
pane.items()
|
||||
.filter_map(|item| item.downcast::<Editor>())
|
||||
@@ -17091,6 +17134,21 @@ impl Editor {
|
||||
});
|
||||
}
|
||||
});
|
||||
cx.defer({
|
||||
let editor = editor.clone();
|
||||
move |cx| {
|
||||
let Some(range) = first_range else { return };
|
||||
editor.update(cx, |editor, cx| {
|
||||
let point = editor
|
||||
.buffer()
|
||||
.read(cx)
|
||||
.snapshot(cx)
|
||||
.summary_for_anchor(&range.start);
|
||||
|
||||
editor.finish_tag_jump(point, cx)
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
let item = Box::new(editor);
|
||||
let item_id = item.item_id();
|
||||
|
||||
@@ -911,7 +911,7 @@ async fn test_navigation_history(cx: &mut TestAppContext) {
|
||||
invalid_anchor.text_anchor.buffer_id = BufferId::new(999).ok();
|
||||
let invalid_point = Point::new(9999, 0);
|
||||
editor.navigate(
|
||||
Box::new(NavigationData {
|
||||
Rc::new(NavigationData {
|
||||
cursor_anchor: invalid_anchor,
|
||||
cursor_position: invalid_point,
|
||||
scroll_anchor: ScrollAnchor {
|
||||
|
||||
@@ -241,6 +241,19 @@ impl Editor {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// todo!()
|
||||
// if let Some(nav_history) = self.nav_history.as_mut() {
|
||||
// nav_history.start_tag_jump(
|
||||
// Some(NavigationData {
|
||||
// cursor_anchor,
|
||||
// cursor_position,
|
||||
// scroll_anchor: scroll_state,
|
||||
// scroll_top_row,
|
||||
// }),
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
let navigate_task =
|
||||
self.navigate_to_hover_links(None, links, modifiers.alt, window, cx);
|
||||
self.select(SelectPhase::End, window, cx);
|
||||
|
||||
@@ -34,6 +34,7 @@ use std::{
|
||||
iter,
|
||||
ops::Range,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
use text::{BufferId, BufferSnapshot, Selection};
|
||||
@@ -589,7 +590,7 @@ impl Item for Editor {
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn std::any::Any>,
|
||||
data: Rc<dyn std::any::Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
|
||||
@@ -17,6 +17,7 @@ use std::{
|
||||
any::{Any, TypeId},
|
||||
fmt::Write as _,
|
||||
path::PathBuf,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
use ui::{
|
||||
@@ -527,12 +528,7 @@ impl Item for CommitView {
|
||||
});
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
fn navigate(&mut self, data: Rc<dyn Any>, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use std::{
|
||||
any::{Any, TypeId},
|
||||
path::PathBuf,
|
||||
pin::pin,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
@@ -301,12 +302,7 @@ impl Item for FileDiffView {
|
||||
});
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
fn navigate(&mut self, data: Rc<dyn Any>, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -32,9 +32,12 @@ use project::{
|
||||
},
|
||||
};
|
||||
use settings::{Settings, SettingsStore};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
rc::Rc,
|
||||
};
|
||||
use theme::ActiveTheme;
|
||||
use ui::{KeyBinding, Tooltip, prelude::*, vertical_divider};
|
||||
use util::{ResultExt as _, rel_path::RelPath};
|
||||
@@ -649,12 +652,7 @@ impl Item for ProjectDiff {
|
||||
.update(cx, |editor, cx| editor.deactivated(window, cx));
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
fn navigate(&mut self, data: Rc<dyn Any>, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use std::{
|
||||
cmp,
|
||||
ops::Range,
|
||||
pin::pin,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
@@ -362,12 +363,7 @@ impl Item for TextDiffView {
|
||||
});
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
fn navigate(&mut self, data: Rc<dyn Any>, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
self.diff_editor
|
||||
.update(cx, |editor, cx| editor.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ use std::{
|
||||
mem,
|
||||
ops::{Not, Range},
|
||||
pin::pin,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
use ui::{IconButtonShape, KeyBinding, Toggleable, Tooltip, prelude::*, utils::SearchInputWidth};
|
||||
@@ -633,12 +634,7 @@ impl Item for ProjectSearchView {
|
||||
});
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
data: Box<dyn Any>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
fn navigate(&mut self, data: Rc<dyn Any>, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
self.results_editor
|
||||
.update(cx, |editor, cx| editor.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ pub trait Item: Focusable + EventEmitter<Self::Event> + Render + Sized {
|
||||
fn discarded(&self, _project: Entity<Project>, _window: &mut Window, _cx: &mut Context<Self>) {}
|
||||
fn on_removed(&self, _cx: &App) {}
|
||||
fn workspace_deactivated(&mut self, _window: &mut Window, _: &mut Context<Self>) {}
|
||||
fn navigate(&mut self, _: Box<dyn Any>, _window: &mut Window, _: &mut Context<Self>) -> bool {
|
||||
fn navigate(&mut self, _: Rc<dyn Any>, _window: &mut Window, _: &mut Context<Self>) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -449,7 +449,7 @@ pub trait ItemHandle: 'static + Send {
|
||||
fn deactivated(&self, window: &mut Window, cx: &mut App);
|
||||
fn on_removed(&self, cx: &App);
|
||||
fn workspace_deactivated(&self, window: &mut Window, cx: &mut App);
|
||||
fn navigate(&self, data: Box<dyn Any>, window: &mut Window, cx: &mut App) -> bool;
|
||||
fn navigate(&self, data: Rc<dyn Any>, window: &mut Window, cx: &mut App) -> bool;
|
||||
fn item_id(&self) -> EntityId;
|
||||
fn to_any(&self) -> AnyView;
|
||||
fn is_dirty(&self, cx: &App) -> bool;
|
||||
@@ -900,7 +900,7 @@ impl<T: Item> ItemHandle for Entity<T> {
|
||||
self.update(cx, |this, cx| this.workspace_deactivated(window, cx));
|
||||
}
|
||||
|
||||
fn navigate(&self, data: Box<dyn Any>, window: &mut Window, cx: &mut App) -> bool {
|
||||
fn navigate(&self, data: Rc<dyn Any>, window: &mut Window, cx: &mut App) -> bool {
|
||||
self.update(cx, |this, cx| this.navigate(data, window, cx))
|
||||
}
|
||||
|
||||
@@ -1277,7 +1277,7 @@ pub mod test {
|
||||
InteractiveElement, IntoElement, Render, SharedString, Task, WeakEntity, Window,
|
||||
};
|
||||
use project::{Project, ProjectEntryId, ProjectPath, WorktreeId};
|
||||
use std::{any::Any, cell::Cell};
|
||||
use std::{any::Any, cell::Cell, rc::Rc};
|
||||
use util::rel_path::rel_path;
|
||||
|
||||
pub struct TestProjectItem {
|
||||
@@ -1510,11 +1510,14 @@ pub mod test {
|
||||
|
||||
fn navigate(
|
||||
&mut self,
|
||||
state: Box<dyn Any>,
|
||||
state: Rc<dyn Any>,
|
||||
_window: &mut Window,
|
||||
_: &mut Context<Self>,
|
||||
) -> bool {
|
||||
let state = *state.downcast::<String>().unwrap_or_default();
|
||||
let state = state
|
||||
.downcast_ref::<String>()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_default();
|
||||
if state != self.state {
|
||||
self.state = state;
|
||||
true
|
||||
|
||||
@@ -211,6 +211,10 @@ actions!(
|
||||
GoBack,
|
||||
/// Navigates forward in history.
|
||||
GoForward,
|
||||
/// Navigates back in the tag stack.
|
||||
GoToOlderTag,
|
||||
/// Navigates forward in the tag stack.
|
||||
GoToNewerTag,
|
||||
/// Joins this pane into the next pane.
|
||||
JoinIntoNext,
|
||||
/// Joins all panes into one.
|
||||
@@ -417,6 +421,9 @@ struct NavHistoryState {
|
||||
backward_stack: VecDeque<NavigationEntry>,
|
||||
forward_stack: VecDeque<NavigationEntry>,
|
||||
closed_stack: VecDeque<NavigationEntry>,
|
||||
tag_stack: VecDeque<(NavigationEntry, NavigationEntry)>,
|
||||
tag_stack_pos: usize,
|
||||
pending_tag_source: Option<NavigationEntry>,
|
||||
paths_by_item: HashMap<EntityId, (ProjectPath, Option<PathBuf>)>,
|
||||
pane: WeakEntity<Pane>,
|
||||
next_timestamp: Arc<AtomicUsize>,
|
||||
@@ -438,9 +445,10 @@ impl Default for NavigationMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NavigationEntry {
|
||||
pub item: Arc<dyn WeakItemHandle>,
|
||||
pub data: Option<Box<dyn Any + Send>>,
|
||||
pub data: Option<Rc<dyn Any + Send>>,
|
||||
pub timestamp: usize,
|
||||
pub is_preview: bool,
|
||||
}
|
||||
@@ -513,6 +521,9 @@ impl Pane {
|
||||
backward_stack: Default::default(),
|
||||
forward_stack: Default::default(),
|
||||
closed_stack: Default::default(),
|
||||
tag_stack: Default::default(),
|
||||
tag_stack_pos: 0,
|
||||
pending_tag_source: None,
|
||||
paths_by_item: Default::default(),
|
||||
pane: handle,
|
||||
next_timestamp,
|
||||
@@ -850,6 +861,24 @@ impl Pane {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn go_to_older_tag(
|
||||
&mut self,
|
||||
_: &GoToOlderTag,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some(workspace) = self.workspace.upgrade() {
|
||||
let pane = cx.entity().downgrade();
|
||||
window.defer(cx, move |window, cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace
|
||||
.navigate_tag_history(pane, window, cx)
|
||||
.detach_and_log_err(cx)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn history_updated(&mut self, cx: &mut Context<Self>) {
|
||||
self.toolbar.update(cx, |_, cx| cx.notify());
|
||||
}
|
||||
@@ -3756,6 +3785,7 @@ impl Render for Pane {
|
||||
.on_action(cx.listener(Pane::toggle_zoom))
|
||||
.on_action(cx.listener(Self::navigate_backward))
|
||||
.on_action(cx.listener(Self::navigate_forward))
|
||||
.on_action(cx.listener(Self::go_to_older_tag))
|
||||
.on_action(
|
||||
cx.listener(|pane: &mut Pane, action: &ActivateItem, window, cx| {
|
||||
pane.activate_item(
|
||||
@@ -3996,8 +4026,40 @@ impl ItemNavHistory {
|
||||
self.history.pop(NavigationMode::GoingBack, cx)
|
||||
}
|
||||
|
||||
pub fn pop_forward(&mut self, cx: &mut App) -> Option<NavigationEntry> {
|
||||
self.history.pop(NavigationMode::GoingForward, cx)
|
||||
pub fn start_tag_jump<D>(&mut self, data: Option<D>, cx: &mut App)
|
||||
where
|
||||
D: 'static + Any + Send,
|
||||
{
|
||||
if self
|
||||
.item
|
||||
.upgrade()
|
||||
.is_some_and(|item| item.include_in_nav_history())
|
||||
{
|
||||
self.history.start_tag_jump(
|
||||
data.map(|data| Rc::new(data) as Rc<dyn Any + Send>),
|
||||
self.item.clone(),
|
||||
self.is_preview,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish_tag_jump<D>(&mut self, data: Option<D>, cx: &mut App)
|
||||
where
|
||||
D: 'static + Any + Send,
|
||||
{
|
||||
if self
|
||||
.item
|
||||
.upgrade()
|
||||
.is_some_and(|item| item.include_in_nav_history())
|
||||
{
|
||||
self.history.finish_tag_jump(
|
||||
data.map(|data| Rc::new(data) as Rc<dyn Any + Send>),
|
||||
self.item.clone(),
|
||||
self.is_preview,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4075,7 +4137,7 @@ impl NavHistory {
|
||||
}
|
||||
state.backward_stack.push_back(NavigationEntry {
|
||||
item,
|
||||
data: data.map(|data| Box::new(data) as Box<dyn Any + Send>),
|
||||
data: data.map(|data| Rc::new(data) as Rc<dyn Any + Send>),
|
||||
timestamp: state.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
||||
is_preview,
|
||||
});
|
||||
@@ -4087,7 +4149,7 @@ impl NavHistory {
|
||||
}
|
||||
state.forward_stack.push_back(NavigationEntry {
|
||||
item,
|
||||
data: data.map(|data| Box::new(data) as Box<dyn Any + Send>),
|
||||
data: data.map(|data| Rc::new(data) as Rc<dyn Any + Send>),
|
||||
timestamp: state.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
||||
is_preview,
|
||||
});
|
||||
@@ -4098,7 +4160,7 @@ impl NavHistory {
|
||||
}
|
||||
state.backward_stack.push_back(NavigationEntry {
|
||||
item,
|
||||
data: data.map(|data| Box::new(data) as Box<dyn Any + Send>),
|
||||
data: data.map(|data| Rc::new(data) as Rc<dyn Any + Send>),
|
||||
timestamp: state.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
||||
is_preview,
|
||||
});
|
||||
@@ -4109,7 +4171,7 @@ impl NavHistory {
|
||||
}
|
||||
state.closed_stack.push_back(NavigationEntry {
|
||||
item,
|
||||
data: data.map(|data| Box::new(data) as Box<dyn Any + Send>),
|
||||
data: data.map(|data| Rc::new(data) as Rc<dyn Any + Send>),
|
||||
timestamp: state.next_timestamp.fetch_add(1, Ordering::SeqCst),
|
||||
is_preview,
|
||||
});
|
||||
@@ -4135,6 +4197,55 @@ impl NavHistory {
|
||||
pub fn path_for_item(&self, item_id: EntityId) -> Option<(ProjectPath, Option<PathBuf>)> {
|
||||
self.0.lock().paths_by_item.get(&item_id).cloned()
|
||||
}
|
||||
|
||||
pub fn start_tag_jump(
|
||||
&mut self,
|
||||
data: Option<Rc<dyn Any + Send>>,
|
||||
item: Arc<dyn WeakItemHandle>,
|
||||
is_preview: bool,
|
||||
_cx: &mut App,
|
||||
) {
|
||||
self.0.lock().pending_tag_source.replace(NavigationEntry {
|
||||
item,
|
||||
data,
|
||||
timestamp: 0,
|
||||
is_preview,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn finish_tag_jump(
|
||||
&mut self,
|
||||
data: Option<Rc<dyn Any + Send>>,
|
||||
item: Arc<dyn WeakItemHandle>,
|
||||
is_preview: bool,
|
||||
_cx: &mut App,
|
||||
) {
|
||||
let mut state = self.0.lock();
|
||||
let Some(source) = state.pending_tag_source.take() else {
|
||||
debug_panic!("Finished tag jump without starting one?");
|
||||
return;
|
||||
};
|
||||
let dest = NavigationEntry {
|
||||
item,
|
||||
data,
|
||||
timestamp: 0,
|
||||
is_preview,
|
||||
};
|
||||
let truncate_to = state.tag_stack_pos;
|
||||
state.tag_stack.truncate(truncate_to);
|
||||
state.tag_stack.push_back((source, dest));
|
||||
state.tag_stack_pos += 1;
|
||||
}
|
||||
|
||||
pub fn tag_stack_back(&mut self) -> Option<NavigationEntry> {
|
||||
let mut state = self.0.lock();
|
||||
if state.tag_stack_pos > 0 {
|
||||
state.tag_stack_pos -= 1;
|
||||
Some(state.tag_stack[state.tag_stack_pos].0.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NavHistoryState {
|
||||
|
||||
@@ -1927,6 +1927,127 @@ impl Workspace {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn navigate_tag_history(
|
||||
&mut self,
|
||||
pane: WeakEntity<Pane>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Workspace>,
|
||||
) -> Task<Result<()>> {
|
||||
let to_load = if let Some(pane) = pane.upgrade() {
|
||||
pane.update(cx, |pane, cx| {
|
||||
window.focus(&pane.focus_handle(cx));
|
||||
loop {
|
||||
// Retrieve the weak item handle from the history.
|
||||
let entry = pane.nav_history_mut().tag_stack_back()?;
|
||||
|
||||
// If the item is still present in this pane, then activate it.
|
||||
if let Some(index) = entry
|
||||
.item
|
||||
.upgrade()
|
||||
.and_then(|v| pane.index_for_item(v.as_ref()))
|
||||
{
|
||||
let prev_active_item_index = pane.active_item_index();
|
||||
pane.activate_item(index, true, true, window, cx);
|
||||
|
||||
let mut navigated = prev_active_item_index != pane.active_item_index();
|
||||
if let Some(data) = entry.data {
|
||||
navigated |= pane.active_item()?.navigate(data, window, cx);
|
||||
}
|
||||
|
||||
if navigated {
|
||||
break None;
|
||||
}
|
||||
} else {
|
||||
// If the item is no longer present in this pane, then retrieve its
|
||||
// path info in order to reopen it.
|
||||
break pane
|
||||
.nav_history()
|
||||
.path_for_item(entry.item.id())
|
||||
.map(|(project_path, abs_path)| (project_path, abs_path, entry));
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some((project_path, abs_path, entry)) = to_load {
|
||||
// If the item was no longer present, then load it again from its previous path, first try the local path
|
||||
let open_by_project_path = self.load_path(project_path.clone(), window, cx);
|
||||
|
||||
cx.spawn_in(window, async move |workspace, cx| {
|
||||
let open_by_project_path = open_by_project_path.await;
|
||||
let mut navigated = false;
|
||||
match open_by_project_path
|
||||
.with_context(|| format!("Navigating to {project_path:?}"))
|
||||
{
|
||||
Ok((project_entry_id, build_item)) => {
|
||||
let prev_active_item_id = pane.update(cx, |pane, _| {
|
||||
pane.active_item().map(|p| p.item_id())
|
||||
})?;
|
||||
|
||||
pane.update_in(cx, |pane, window, cx| {
|
||||
let item = pane.open_item(
|
||||
project_entry_id,
|
||||
project_path,
|
||||
true,
|
||||
entry.is_preview,
|
||||
true,
|
||||
None,
|
||||
window, cx,
|
||||
build_item,
|
||||
);
|
||||
navigated |= Some(item.item_id()) != prev_active_item_id;
|
||||
if let Some(data) = entry.data {
|
||||
navigated |= item.navigate(data, window, cx);
|
||||
}
|
||||
})?;
|
||||
}
|
||||
Err(open_by_project_path_e) => {
|
||||
// Fall back to opening by abs path, in case an external file was opened and closed,
|
||||
// and its worktree is now dropped
|
||||
if let Some(abs_path) = abs_path {
|
||||
let prev_active_item_id = pane.update(cx, |pane, _| {
|
||||
pane.active_item().map(|p| p.item_id())
|
||||
})?;
|
||||
let open_by_abs_path = workspace.update_in(cx, |workspace, window, cx| {
|
||||
workspace.open_abs_path(abs_path.clone(), OpenOptions { visible: Some(OpenVisible::None), ..Default::default() }, window, cx)
|
||||
})?;
|
||||
match open_by_abs_path
|
||||
.await
|
||||
.with_context(|| format!("Navigating to {abs_path:?}"))
|
||||
{
|
||||
Ok(item) => {
|
||||
pane.update_in(cx, |pane, window, cx| {
|
||||
navigated |= Some(item.item_id()) != prev_active_item_id;
|
||||
if let Some(data) = entry.data {
|
||||
navigated |= item.navigate(data, window, cx);
|
||||
}
|
||||
})?;
|
||||
}
|
||||
Err(open_by_abs_path_e) => {
|
||||
log::error!("Failed to navigate history: {open_by_project_path_e:#} and {open_by_abs_path_e:#}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !navigated {
|
||||
workspace
|
||||
.update_in(cx, |workspace, window, cx| {
|
||||
Self::navigate_tag_history(workspace, pane, window, cx)
|
||||
})?
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
} else {
|
||||
Task::ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn navigate_history(
|
||||
&mut self,
|
||||
pane: WeakEntity<Pane>,
|
||||
|
||||
Reference in New Issue
Block a user