Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 175 additions & 5 deletions crates/git_ui/src/git_graph.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
commit_tooltip::{CommitAvatar, CommitDetails, CommitTooltip},
commit_view::CommitView,
git_panel_settings::GitPanelSettings,
git_status_icon,
};
use collections::{BTreeMap, HashMap, IndexSet};
Expand Down Expand Up @@ -39,6 +40,7 @@ use search::{
SearchOption, SearchOptions, SearchSource, SelectNextMatch, SelectPreviousMatch,
ToggleCaseSensitive, buffer_search,
};
use settings::{Settings, update_settings_file};
use smallvec::{SmallVec, smallvec};
use std::{
cell::Cell,
Expand All @@ -51,8 +53,8 @@ use task::{ResolvedTask, TaskContext, TaskVariables, VariableName};
use theme::AccentColors;
use time::{OffsetDateTime, UtcOffset, format_description::BorrowedFormatItem};
use ui::{
Chip, ColumnWidthConfig, CommonAnimationExt as _, ContextMenu, ContextMenuEntry, DiffStat,
Divider, HeaderResizeInfo, HighlightedLabel, IndentGuideColors, ListItem, ListItemSpacing,
Checkbox, Chip, ColumnWidthConfig, CommonAnimationExt as _, ContextMenu, ContextMenuEntry,
DiffStat, Divider, HeaderResizeInfo, HighlightedLabel, IndentGuideColors, ListItem, ListItemSpacing,
RedistributableColumnsState, ScrollableHandle, Table, TableInteractionState,
TableRenderContext, TableResizeBehavior, Tooltip, WithScrollbar, bind_redistributable_columns,
prelude::*, redistribute_hidden_fractions, redistribute_hidden_widths,
Expand Down Expand Up @@ -1338,9 +1340,52 @@ pub struct GitGraph {
changed_files_view_mode: ChangedFilesViewMode,
changed_files_expanded_dirs: HashMap<RepoPath, bool>,
pending_select_sha: Option<Oid>,
show_stashes_in_graph: bool,
}

impl GitGraph {
fn should_show_stashes(cx: &App) -> bool {
GitPanelSettings::get_global(cx).show_stashes_in_graph
}

fn is_stash_commit(commit: &InitialGraphCommitData) -> bool {
commit
.ref_names
.iter()
.any(|ref_name| ref_name.as_ref() == "refs/stash")
}

fn visible_graph_commits(
&self,
commits: &[Arc<InitialGraphCommitData>],
) -> Vec<Arc<InitialGraphCommitData>> {
if self.show_stashes_in_graph {
commits.to_vec()
} else {
commits
.iter()
.filter(|commit| !Self::is_stash_commit(commit))
.cloned()
.collect()
}
}

fn toggle_show_stashes_in_graph(&mut self, cx: &mut Context<Self>) {
let new_value = !self.show_stashes_in_graph;
self.show_stashes_in_graph = new_value;

if let Some(workspace) = self.workspace.upgrade() {
let fs = workspace.read(cx).app_state().fs.clone();
update_settings_file(fs, cx, move |settings, _| {
settings.git_panel.get_or_insert_default().show_stashes_in_graph = Some(new_value);
});
}

self.pending_select_sha = None;
self.invalidate_state(cx);
self.fetch_initial_graph_data(cx);
}

fn invalidate_state(&mut self, cx: &mut Context<Self>) {
self.graph_data.clear();
self.search_state.matches.clear();
Expand Down Expand Up @@ -1536,9 +1581,11 @@ impl GitGraph {
},
);
let mut row_height = Self::row_height(window, cx);
let mut show_stashes_in_graph = Self::should_show_stashes(cx);

cx.observe_global_in::<settings::SettingsStore>(window, move |this, window, cx| {
let new_row_height = Self::row_height(window, cx);
let new_show_stashes_in_graph = Self::should_show_stashes(cx);
if new_row_height != row_height {
// The `uniform_list` powering the table caches the item size
// from its last layout; invalidate it so it re-measures with
Expand All @@ -1549,6 +1596,13 @@ impl GitGraph {
row_height = new_row_height;
cx.notify();
}
if new_show_stashes_in_graph != show_stashes_in_graph {
show_stashes_in_graph = new_show_stashes_in_graph;
this.show_stashes_in_graph = new_show_stashes_in_graph;
this.pending_select_sha = None;
this.invalidate_state(cx);
this.fetch_initial_graph_data(cx);
}
})
.detach();

Expand Down Expand Up @@ -1584,6 +1638,7 @@ impl GitGraph {
changed_files_view_mode: ChangedFilesViewMode::default(),
changed_files_expanded_dirs: HashMap::default(),
pending_select_sha: None,
show_stashes_in_graph: Self::should_show_stashes(cx),
};

this.fetch_initial_graph_data(cx);
Expand Down Expand Up @@ -1639,7 +1694,8 @@ impl GitGraph {
old_count..*commit_count,
cx,
);
self.graph_data.add_commits(commits);
let commits = self.visible_graph_commits(commits);
self.graph_data.add_commits(&commits);

let pending_sha_index = self.pending_select_sha.and_then(|oid| {
repository.get_graph_data(source.clone(), *order).and_then(
Expand Down Expand Up @@ -1671,7 +1727,9 @@ impl GitGraph {
self.invalidate_state(cx);
}
}
RepositoryEvent::StashEntriesChanged if self.log_source == LogSource::All => {
RepositoryEvent::StashEntriesChanged
if self.log_source == LogSource::All && self.show_stashes_in_graph =>
{
// Stash entries initial's scan id is 2, so we don't want to invalidate the graph before that
if repository.read(cx).scan_id > 2 {
self.pending_select_sha = None;
Expand All @@ -1689,7 +1747,8 @@ impl GitGraph {
let commits = repository
.graph_data(self.log_source.clone(), self.log_order, 0..usize::MAX, cx)
.commits;
self.graph_data.add_commits(commits);
let commits = self.visible_graph_commits(commits);
self.graph_data.add_commits(&commits);
});
}
}
Expand Down Expand Up @@ -2747,6 +2806,7 @@ impl GitGraph {

let focus_handle = self.focus_handle.clone();
let git_graph = cx.entity();
let show_stashes_in_graph = self.show_stashes_in_graph;
let context_menu = ContextMenu::build(window, cx, |mut context_menu, _window, _cx| {
context_menu = context_menu.context(focus_handle).header("Columns");
for (col_idx, label) in columns.iter().enumerate() {
Expand All @@ -2768,6 +2828,20 @@ impl GitGraph {
},
);
}
if !is_path_history {
let git_graph = git_graph.clone();
context_menu = context_menu.separator().toggleable_entry(
"Show Stashes",
show_stashes_in_graph,
IconPosition::End,
None,
move |_window, cx| {
git_graph.update(cx, |this, cx| {
this.toggle_show_stashes_in_graph(cx);
});
},
);
}
context_menu
});

Expand Down Expand Up @@ -2905,6 +2979,23 @@ impl GitGraph {
),
),
)
.when(matches!(self.log_source, LogSource::All), |this| {
this.child(
h_flex()
.gap_1()
.items_center()
.child(
Checkbox::new(
"git-graph-show-stashes",
self.show_stashes_in_graph.into(),
)
.on_click(cx.listener(|this, _, _, cx| {
this.toggle_show_stashes_in_graph(cx);
})),
)
.child(Label::new("Show stashes").size(LabelSize::Small)),
)
})
}

fn render_loading_spinner(&self, cx: &App) -> AnyElement {
Expand Down Expand Up @@ -6587,6 +6678,85 @@ mod tests {
assert_eq!(reloaded_shas, vec![updated_head, updated_stash]);
}

#[gpui::test]
async fn test_git_graph_hides_stashes_when_setting_disabled(cx: &mut TestAppContext) {
init_test(cx);

cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings(cx, |settings| {
settings.git_panel.get_or_insert_default().show_stashes_in_graph = Some(false);
});
});
});

let fs = FakeFs::new(cx.executor());
fs.insert_tree(
Path::new("/project"),
json!({
".git": {},
"file.txt": "content",
}),
)
.await;

let head = Oid::from_bytes(&[1; 20]).unwrap();
let stash = Oid::from_bytes(&[2; 20]).unwrap();

fs.set_graph_commits(
Path::new("/project/.git"),
vec![
Arc::new(InitialGraphCommitData {
sha: head,
parents: smallvec![stash],
ref_names: vec!["HEAD".into(), "refs/heads/main".into()],
}),
Arc::new(InitialGraphCommitData {
sha: stash,
parents: smallvec![],
ref_names: vec!["refs/stash".into()],
}),
],
);

let project = Project::test(fs.clone(), [Path::new("/project")], cx).await;
cx.run_until_parked();

let repository = project.read_with(cx, |project, cx| {
project
.active_repository(cx)
.expect("should have a repository")
});

let (multi_workspace, cx) = cx.add_window_view(|window, cx| {
workspace::MultiWorkspace::test_new(project.clone(), window, cx)
});
let workspace_weak =
multi_workspace.read_with(&*cx, |multi, _| multi.workspace().downgrade());
let git_graph = cx.new_window_entity(|window, cx| {
GitGraph::new(
repository.read(cx).id,
project.read(cx).git_store().clone(),
workspace_weak,
None,
window,
cx,
)
});
cx.run_until_parked();

let shas = git_graph.read_with(&*cx, |graph, _| {
graph
.graph_data
.commits
.iter()
.map(|commit| commit.data.sha)
.collect::<Vec<_>>()
});

assert_eq!(shas, vec![head]);
}

#[gpui::test]
async fn test_git_graph_row_at_position_rounding(cx: &mut TestAppContext) {
init_test(cx);
Expand Down
2 changes: 2 additions & 0 deletions crates/git_ui/src/git_panel_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub struct GitPanelSettings {
pub sort_by: GitPanelSortBy,
pub group_by: GitPanelGroupBy,
pub collapse_untracked_diff: bool,
pub show_stashes_in_graph: bool,
pub tree_view: bool,
pub diff_stats: bool,
pub show_count_badge: bool,
Expand Down Expand Up @@ -78,6 +79,7 @@ impl Settings for GitPanelSettings {
sort_by: git_panel.sort_by.unwrap(),
group_by: git_panel.group_by.unwrap(),
collapse_untracked_diff: git_panel.collapse_untracked_diff.unwrap(),
show_stashes_in_graph: git_panel.show_stashes_in_graph.unwrap_or(true),
tree_view: git_panel.tree_view.unwrap(),
diff_stats: git_panel.diff_stats.unwrap(),
show_count_badge: git_panel.show_count_badge.unwrap(),
Expand Down
5 changes: 5 additions & 0 deletions crates/settings_content/src/settings_content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,11 @@ pub struct GitPanelSettingsContent {
/// Default: false
pub collapse_untracked_diff: Option<bool>,

/// Whether to show stash entries in the Git Graph.
///
/// Default: true
pub show_stashes_in_graph: Option<bool>,

/// Whether to show entries with tree or flat view in the panel
///
/// Default: false
Expand Down
25 changes: 24 additions & 1 deletion crates/settings_ui/src/page_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5840,7 +5840,7 @@ fn panels_page() -> SettingsPage {
]
}

fn git_panel_section() -> [SettingsPageItem; 17] {
fn git_panel_section() -> [SettingsPageItem; 18] {
[
SettingsPageItem::SectionHeader("Git Panel"),
SettingsPageItem::SettingItem(SettingItem {
Expand Down Expand Up @@ -5983,6 +5983,29 @@ fn panels_page() -> SettingsPage {
metadata: None,
files: USER,
}),
SettingsPageItem::SettingItem(SettingItem {
title: "Show Stashes In Git Graph",
description: "Whether to include stash entries when viewing the Git Graph.",
field: Box::new(SettingField {
organization_override: None,
json_path: Some("git_panel.show_stashes_in_graph"),
pick: |settings_content| {
settings_content
.git_panel
.as_ref()?
.show_stashes_in_graph
.as_ref()
},
write: |settings_content, value, _| {
settings_content
.git_panel
.get_or_insert_default()
.show_stashes_in_graph = value;
},
}),
metadata: None,
files: USER,
}),
SettingsPageItem::SettingItem(SettingItem {
title: "Tree View",
description: "Enable to show entries in tree view list, disable to show in flat view list.",
Expand Down
Loading