mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-04 18:15:21 +00:00
Rework the way project panel auto reveals entries
* gitignored entries are never auto revealed * `project_panel::auto_reveal_entries = true` settings entry was added, setting it to `false` will disable the auto reveal * `pane::RevealInProjectPanel` action was added that activates the project panel and reveals the entry it got triggered on (including the gitignored ones)
This commit is contained in:
parent
a9f817fc14
commit
27d6432c84
8 changed files with 136 additions and 76 deletions
|
@ -143,7 +143,11 @@
|
||||||
// Whether to show the git status in the project panel.
|
// Whether to show the git status in the project panel.
|
||||||
"git_status": true,
|
"git_status": true,
|
||||||
// Amount of indentation for nested items.
|
// Amount of indentation for nested items.
|
||||||
"indent_size": 20
|
"indent_size": 20,
|
||||||
|
// Whether to reveal it in the project panel automatically,
|
||||||
|
// when a corresponding project entry becomes active.
|
||||||
|
// Gitignored entries are never auto revealed.
|
||||||
|
"auto_reveal_entries": true
|
||||||
},
|
},
|
||||||
"collaboration_panel": {
|
"collaboration_panel": {
|
||||||
// Whether to show the collaboration panel button in the status bar.
|
// Whether to show the collaboration panel button in the status bar.
|
||||||
|
|
|
@ -1189,7 +1189,7 @@ impl CursorPosition {
|
||||||
impl Render for CursorPosition {
|
impl Render for CursorPosition {
|
||||||
type Element = Div;
|
type Element = Div;
|
||||||
|
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
|
||||||
div().when_some(self.position, |el, position| {
|
div().when_some(self.position, |el, position| {
|
||||||
let mut text = format!(
|
let mut text = format!(
|
||||||
"{}{FILE_ROW_COLUMN_DELIMITER}{}",
|
"{}{FILE_ROW_COLUMN_DELIMITER}{}",
|
||||||
|
|
|
@ -301,6 +301,7 @@ pub enum Event {
|
||||||
CollaboratorJoined(proto::PeerId),
|
CollaboratorJoined(proto::PeerId),
|
||||||
CollaboratorLeft(proto::PeerId),
|
CollaboratorLeft(proto::PeerId),
|
||||||
RefreshInlayHints,
|
RefreshInlayHints,
|
||||||
|
RevealInProjectPanel(ProjectEntryId),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum LanguageServerState {
|
pub enum LanguageServerState {
|
||||||
|
|
|
@ -199,14 +199,14 @@ impl ProjectPanel {
|
||||||
.detach();
|
.detach();
|
||||||
cx.subscribe(&project, |this, project, event, cx| match event {
|
cx.subscribe(&project, |this, project, event, cx| match event {
|
||||||
project::Event::ActiveEntryChanged(Some(entry_id)) => {
|
project::Event::ActiveEntryChanged(Some(entry_id)) => {
|
||||||
if let Some(worktree_id) = project.read(cx).worktree_id_for_entry(*entry_id, cx)
|
if settings::get::<ProjectPanelSettings>(cx).auto_reveal_entries {
|
||||||
{
|
this.reveal_entry(project, *entry_id, true, cx);
|
||||||
this.expand_entry(worktree_id, *entry_id, cx);
|
|
||||||
this.update_visible_entries(Some((worktree_id, *entry_id)), cx);
|
|
||||||
this.autoscroll(cx);
|
|
||||||
cx.notify();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
project::Event::RevealInProjectPanel(entry_id) => {
|
||||||
|
this.reveal_entry(project, *entry_id, false, cx);
|
||||||
|
cx.emit(Event::ActivatePanel);
|
||||||
|
}
|
||||||
project::Event::ActivateProjectPanel => {
|
project::Event::ActivateProjectPanel => {
|
||||||
cx.emit(Event::ActivatePanel);
|
cx.emit(Event::ActivatePanel);
|
||||||
}
|
}
|
||||||
|
@ -1531,6 +1531,32 @@ impl ProjectPanel {
|
||||||
.with_cursor_style(CursorStyle::PointingHand)
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
.into_any_named("project panel entry")
|
.into_any_named("project panel entry")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO kb tests
|
||||||
|
fn reveal_entry(
|
||||||
|
&mut self,
|
||||||
|
project: ModelHandle<Project>,
|
||||||
|
entry_id: ProjectEntryId,
|
||||||
|
skip_ignored: bool,
|
||||||
|
cx: &mut ViewContext<'_, '_, ProjectPanel>,
|
||||||
|
) {
|
||||||
|
if let Some(worktree) = project.read(cx).worktree_for_entry(entry_id, cx) {
|
||||||
|
let worktree = worktree.read(cx);
|
||||||
|
if skip_ignored
|
||||||
|
&& worktree
|
||||||
|
.entry_for_id(entry_id)
|
||||||
|
.map_or(true, |entry| entry.is_ignored)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let worktree_id = worktree.id();
|
||||||
|
self.expand_entry(worktree_id, entry_id, cx);
|
||||||
|
self.update_visible_entries(Some((worktree_id, entry_id)), cx);
|
||||||
|
self.autoscroll(cx);
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for ProjectPanel {
|
impl View for ProjectPanel {
|
||||||
|
|
|
@ -18,6 +18,7 @@ pub struct ProjectPanelSettings {
|
||||||
pub folder_icons: bool,
|
pub folder_icons: bool,
|
||||||
pub git_status: bool,
|
pub git_status: bool,
|
||||||
pub indent_size: f32,
|
pub indent_size: f32,
|
||||||
|
pub auto_reveal_entries: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
|
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
|
||||||
|
@ -28,6 +29,7 @@ pub struct ProjectPanelSettingsContent {
|
||||||
pub folder_icons: Option<bool>,
|
pub folder_icons: Option<bool>,
|
||||||
pub git_status: Option<bool>,
|
pub git_status: Option<bool>,
|
||||||
pub indent_size: Option<f32>,
|
pub indent_size: Option<f32>,
|
||||||
|
pub auto_reveal_entries: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Setting for ProjectPanelSettings {
|
impl Setting for ProjectPanelSettings {
|
||||||
|
|
|
@ -96,6 +96,12 @@ pub struct CloseAllItems {
|
||||||
pub save_intent: Option<SaveIntent>,
|
pub save_intent: Option<SaveIntent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RevealInProjectPanel {
|
||||||
|
pub entry_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
pane,
|
pane,
|
||||||
[
|
[
|
||||||
|
@ -116,7 +122,15 @@ actions!(
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
impl_actions!(pane, [ActivateItem, CloseActiveItem, CloseAllItems]);
|
impl_actions!(
|
||||||
|
pane,
|
||||||
|
[
|
||||||
|
ActivateItem,
|
||||||
|
CloseActiveItem,
|
||||||
|
CloseAllItems,
|
||||||
|
RevealInProjectPanel,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
|
const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
|
||||||
|
|
||||||
|
@ -146,6 +160,13 @@ pub fn init(cx: &mut AppContext) {
|
||||||
cx.add_action(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx));
|
cx.add_action(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx));
|
||||||
cx.add_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx));
|
cx.add_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx));
|
||||||
cx.add_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx));
|
cx.add_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx));
|
||||||
|
cx.add_action(|pane: &mut Pane, action: &RevealInProjectPanel, cx| {
|
||||||
|
pane.project.update(cx, |_, cx| {
|
||||||
|
cx.emit(project::Event::RevealInProjectPanel(
|
||||||
|
ProjectEntryId::from_proto(action.entry_id),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1232,80 +1253,87 @@ impl Pane {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
let active_item_id = self.items[self.active_item_index].id();
|
let active_item_id = self.items[self.active_item_index].id();
|
||||||
|
let single_entry_to_resolve =
|
||||||
|
self.items()
|
||||||
|
.find(|i| i.id() == target_item_id)
|
||||||
|
.and_then(|i| {
|
||||||
|
let item_entries = i.project_entry_ids(cx);
|
||||||
|
if item_entries.len() == 1 {
|
||||||
|
Some(item_entries[0])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
let is_active_item = target_item_id == active_item_id;
|
let is_active_item = target_item_id == active_item_id;
|
||||||
let target_pane = cx.weak_handle();
|
let target_pane = cx.weak_handle();
|
||||||
|
|
||||||
// The `CloseInactiveItems` action should really be called "CloseOthers" and the behaviour should be dynamically based on the tab the action is ran on. Currently, this is a weird action because you can run it on a non-active tab and it will close everything by the actual active tab
|
// The `CloseInactiveItems` action should really be called "CloseOthers" and the behaviour should be dynamically based on the tab the action is ran on. Currently, this is a weird action because you can run it on a non-active tab and it will close everything by the actual active tab
|
||||||
|
|
||||||
self.tab_context_menu.update(cx, |menu, cx| {
|
self.tab_context_menu.update(cx, |menu, cx| {
|
||||||
menu.show(
|
let mut menu_items = if is_active_item {
|
||||||
position,
|
vec![
|
||||||
AnchorCorner::TopLeft,
|
ContextMenuItem::action(
|
||||||
if is_active_item {
|
"Close Active Item",
|
||||||
vec![
|
CloseActiveItem { save_intent: None },
|
||||||
ContextMenuItem::action(
|
),
|
||||||
"Close Active Item",
|
ContextMenuItem::action("Close Inactive Items", CloseInactiveItems),
|
||||||
CloseActiveItem { save_intent: None },
|
ContextMenuItem::action("Close Clean Items", CloseCleanItems),
|
||||||
),
|
ContextMenuItem::action("Close Items To The Left", CloseItemsToTheLeft),
|
||||||
ContextMenuItem::action("Close Inactive Items", CloseInactiveItems),
|
ContextMenuItem::action("Close Items To The Right", CloseItemsToTheRight),
|
||||||
ContextMenuItem::action("Close Clean Items", CloseCleanItems),
|
ContextMenuItem::action("Close All Items", CloseAllItems { save_intent: None }),
|
||||||
ContextMenuItem::action("Close Items To The Left", CloseItemsToTheLeft),
|
]
|
||||||
ContextMenuItem::action("Close Items To The Right", CloseItemsToTheRight),
|
} else {
|
||||||
ContextMenuItem::action(
|
// In the case of the user right clicking on a non-active tab, for some item-closing commands, we need to provide the id of the tab, for the others, we can reuse the existing command.
|
||||||
"Close All Items",
|
vec![
|
||||||
CloseAllItems { save_intent: None },
|
ContextMenuItem::handler("Close Inactive Item", {
|
||||||
),
|
let pane = target_pane.clone();
|
||||||
]
|
move |cx| {
|
||||||
} else {
|
if let Some(pane) = pane.upgrade(cx) {
|
||||||
// In the case of the user right clicking on a non-active tab, for some item-closing commands, we need to provide the id of the tab, for the others, we can reuse the existing command.
|
pane.update(cx, |pane, cx| {
|
||||||
vec![
|
pane.close_item_by_id(target_item_id, SaveIntent::Close, cx)
|
||||||
ContextMenuItem::handler("Close Inactive Item", {
|
|
||||||
let pane = target_pane.clone();
|
|
||||||
move |cx| {
|
|
||||||
if let Some(pane) = pane.upgrade(cx) {
|
|
||||||
pane.update(cx, |pane, cx| {
|
|
||||||
pane.close_item_by_id(
|
|
||||||
target_item_id,
|
|
||||||
SaveIntent::Close,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.detach_and_log_err(cx);
|
.detach_and_log_err(cx);
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
ContextMenuItem::action("Close Inactive Items", CloseInactiveItems),
|
}),
|
||||||
ContextMenuItem::action("Close Clean Items", CloseCleanItems),
|
ContextMenuItem::action("Close Inactive Items", CloseInactiveItems),
|
||||||
ContextMenuItem::handler("Close Items To The Left", {
|
ContextMenuItem::action("Close Clean Items", CloseCleanItems),
|
||||||
let pane = target_pane.clone();
|
ContextMenuItem::handler("Close Items To The Left", {
|
||||||
move |cx| {
|
let pane = target_pane.clone();
|
||||||
if let Some(pane) = pane.upgrade(cx) {
|
move |cx| {
|
||||||
pane.update(cx, |pane, cx| {
|
if let Some(pane) = pane.upgrade(cx) {
|
||||||
pane.close_items_to_the_left_by_id(target_item_id, cx)
|
pane.update(cx, |pane, cx| {
|
||||||
.detach_and_log_err(cx);
|
pane.close_items_to_the_left_by_id(target_item_id, cx)
|
||||||
})
|
.detach_and_log_err(cx);
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
ContextMenuItem::handler("Close Items To The Right", {
|
}),
|
||||||
let pane = target_pane.clone();
|
ContextMenuItem::handler("Close Items To The Right", {
|
||||||
move |cx| {
|
let pane = target_pane.clone();
|
||||||
if let Some(pane) = pane.upgrade(cx) {
|
move |cx| {
|
||||||
pane.update(cx, |pane, cx| {
|
if let Some(pane) = pane.upgrade(cx) {
|
||||||
pane.close_items_to_the_right_by_id(target_item_id, cx)
|
pane.update(cx, |pane, cx| {
|
||||||
.detach_and_log_err(cx);
|
pane.close_items_to_the_right_by_id(target_item_id, cx)
|
||||||
})
|
.detach_and_log_err(cx);
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
ContextMenuItem::action(
|
}),
|
||||||
"Close All Items",
|
ContextMenuItem::action("Close All Items", CloseAllItems { save_intent: None }),
|
||||||
CloseAllItems { save_intent: None },
|
]
|
||||||
),
|
};
|
||||||
]
|
|
||||||
},
|
if let Some(entry) = single_entry_to_resolve {
|
||||||
cx,
|
menu_items.push(ContextMenuItem::Separator);
|
||||||
);
|
menu_items.push(ContextMenuItem::action(
|
||||||
|
"Reveal In Project Panel",
|
||||||
|
RevealInProjectPanel {
|
||||||
|
entry_id: entry.to_proto(),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.show(position, AnchorCorner::TopLeft, menu_items, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{
|
se crate::{
|
||||||
item::{ClosePosition, Item, ItemHandle, ItemSettings, WeakItemHandle},
|
item::{ClosePosition, Item, ItemHandle, ItemSettings, WeakItemHandle},
|
||||||
toolbar::Toolbar,
|
toolbar::Toolbar,
|
||||||
workspace_settings::{AutosaveSetting, WorkspaceSettings},
|
workspace_settings::{AutosaveSetting, WorkspaceSettings},
|
||||||
|
|
|
@ -130,7 +130,6 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
|
||||||
let vim_mode_indicator = cx.build_view(|cx| vim::ModeIndicator::new(cx));
|
let vim_mode_indicator = cx.build_view(|cx| vim::ModeIndicator::new(cx));
|
||||||
let feedback_button = cx
|
let feedback_button = cx
|
||||||
.build_view(|_| feedback::deploy_feedback_button::DeployFeedbackButton::new(workspace));
|
.build_view(|_| feedback::deploy_feedback_button::DeployFeedbackButton::new(workspace));
|
||||||
// let cursor_position = cx.add_view(|_| editor::items::CursorPosition::new());
|
|
||||||
let cursor_position = cx.build_view(|_| editor::items::CursorPosition::new());
|
let cursor_position = cx.build_view(|_| editor::items::CursorPosition::new());
|
||||||
workspace.status_bar().update(cx, |status_bar, cx| {
|
workspace.status_bar().update(cx, |status_bar, cx| {
|
||||||
status_bar.add_left_item(diagnostic_summary, cx);
|
status_bar.add_left_item(diagnostic_summary, cx);
|
||||||
|
|
Loading…
Reference in a new issue