mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 20:01:33 +00:00
Alternate files with ctrl-6 (#11367)
This is my stab at #7709 I realize the code is flawed. There's no test coverage, I'm using `clone()` and there are probably better ways to hook into the events. Also, I didn't know what context to use for the keybinding. But maybe with some pointers from someone who actually know what they're doing, I can get this shippable. Release Notes: - vim: Added ctrl-6 for [alternate-file](https://vimhelp.org/editing.txt.html#CTRL-%5E) to navigate back and forth between two buffers. https://github.com/zed-industries/zed/assets/261929/2d10494e-5668-4988-b7b4-417c922d6c61 --------- Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
parent
0d26beb91b
commit
80d3eafa30
4 changed files with 60 additions and 0 deletions
|
@ -1,4 +1,10 @@
|
|||
[
|
||||
{
|
||||
"context": "ProjectPanel || Editor",
|
||||
"bindings": {
|
||||
"ctrl-6": "pane::AlternateFile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "Editor && VimControl && !VimWaiting && !menu",
|
||||
"bindings": {
|
||||
|
|
|
@ -330,6 +330,7 @@ pub trait ItemHandle: 'static + Send {
|
|||
fn serialized_item_kind(&self) -> Option<&'static str>;
|
||||
fn show_toolbar(&self, cx: &AppContext) -> bool;
|
||||
fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Point<Pixels>>;
|
||||
fn downgrade_item(&self) -> Box<dyn WeakItemHandle>;
|
||||
}
|
||||
|
||||
pub trait WeakItemHandle: Send + Sync {
|
||||
|
@ -702,6 +703,10 @@ impl<T: Item> ItemHandle for View<T> {
|
|||
fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Point<Pixels>> {
|
||||
self.read(cx).pixel_position_of_cursor(cx)
|
||||
}
|
||||
|
||||
fn downgrade_item(&self) -> Box<dyn WeakItemHandle> {
|
||||
Box::new(self.downgrade())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<dyn ItemHandle>> for AnyView {
|
||||
|
|
|
@ -18,6 +18,7 @@ use gpui::{
|
|||
MouseDownEvent, NavigationDirection, Pixels, Point, PromptLevel, Render, ScrollHandle,
|
||||
Subscription, Task, View, ViewContext, VisualContext, WeakFocusHandle, WeakView, WindowContext,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use parking_lot::Mutex;
|
||||
use project::{Project, ProjectEntryId, ProjectPath};
|
||||
use serde::Deserialize;
|
||||
|
@ -114,6 +115,7 @@ actions!(
|
|||
ActivatePrevItem,
|
||||
ActivateNextItem,
|
||||
ActivateLastItem,
|
||||
AlternateFile,
|
||||
CloseCleanItems,
|
||||
CloseItemsToTheLeft,
|
||||
CloseItemsToTheRight,
|
||||
|
@ -183,6 +185,10 @@ impl fmt::Debug for Event {
|
|||
/// responsible for managing item tabs, focus and zoom states and drag and drop features.
|
||||
/// Can be split, see `PaneGroup` for more details.
|
||||
pub struct Pane {
|
||||
alternate_file_items: (
|
||||
Option<Box<dyn WeakItemHandle>>,
|
||||
Option<Box<dyn WeakItemHandle>>,
|
||||
),
|
||||
focus_handle: FocusHandle,
|
||||
items: Vec<Box<dyn ItemHandle>>,
|
||||
activation_history: Vec<EntityId>,
|
||||
|
@ -286,6 +292,7 @@ impl Pane {
|
|||
|
||||
let handle = cx.view().downgrade();
|
||||
Self {
|
||||
alternate_file_items: (None, None),
|
||||
focus_handle,
|
||||
items: Vec::new(),
|
||||
activation_history: Vec::new(),
|
||||
|
@ -390,6 +397,39 @@ impl Pane {
|
|||
}
|
||||
}
|
||||
|
||||
fn alternate_file(&mut self, cx: &mut ViewContext<Pane>) {
|
||||
let (_, alternative) = &self.alternate_file_items;
|
||||
if let Some(alternative) = alternative {
|
||||
let existing = self
|
||||
.items()
|
||||
.find_position(|item| item.item_id() == alternative.id());
|
||||
if let Some((ix, _)) = existing {
|
||||
self.activate_item(ix, true, true, cx);
|
||||
} else {
|
||||
if let Some(upgraded) = alternative.upgrade() {
|
||||
self.add_item(upgraded, true, true, None, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn track_alternate_file_items(&mut self) {
|
||||
if let Some(item) = self.active_item().map(|item| item.downgrade_item()) {
|
||||
let (current, _) = &self.alternate_file_items;
|
||||
match current {
|
||||
Some(current) => {
|
||||
if current.id() != item.id() {
|
||||
self.alternate_file_items =
|
||||
(Some(item), self.alternate_file_items.0.take());
|
||||
}
|
||||
}
|
||||
None => {
|
||||
self.alternate_file_items = (Some(item), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_focus(&self, cx: &WindowContext) -> bool {
|
||||
// We not only check whether our focus handle contains focus, but also
|
||||
// whether the active_item might have focus, because we might have just activated an item
|
||||
|
@ -1981,6 +2021,9 @@ impl Render for Pane {
|
|||
.size_full()
|
||||
.flex_none()
|
||||
.overflow_hidden()
|
||||
.on_action(cx.listener(|pane, _: &AlternateFile, cx| {
|
||||
pane.alternate_file(cx);
|
||||
}))
|
||||
.on_action(cx.listener(|pane, _: &SplitLeft, cx| pane.split(SplitDirection::Left, cx)))
|
||||
.on_action(cx.listener(|pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx)))
|
||||
.on_action(
|
||||
|
|
|
@ -2499,6 +2499,9 @@ impl Workspace {
|
|||
self.zoomed_position = None;
|
||||
cx.emit(Event::ZoomChanged);
|
||||
self.update_active_view_for_followers(cx);
|
||||
pane.model.update(cx, |pane, _| {
|
||||
pane.track_alternate_file_items();
|
||||
});
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
@ -2516,6 +2519,9 @@ impl Workspace {
|
|||
}
|
||||
pane::Event::Remove => self.remove_pane(pane, cx),
|
||||
pane::Event::ActivateItem { local } => {
|
||||
pane.model.update(cx, |pane, _| {
|
||||
pane.track_alternate_file_items();
|
||||
});
|
||||
if *local {
|
||||
self.unfollow(&pane, cx);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue