Add staged checkboxes to multibuffer headers (#24308)
Co-authored-by: Mikayla <mikayla@zed.dev> Release Notes: - N/A --------- Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
parent
0671be215f
commit
5d1c56829a
6 changed files with 151 additions and 37 deletions
|
@ -14,8 +14,9 @@ use git::repository::RepoPath;
|
|||
use git::status::FileStatus;
|
||||
use git::{CommitAllChanges, CommitChanges, ToggleStaged};
|
||||
use gpui::*;
|
||||
use language::Buffer;
|
||||
use language::{Buffer, File};
|
||||
use menu::{SelectFirst, SelectLast, SelectNext, SelectPrev};
|
||||
use multi_buffer::ExcerptInfo;
|
||||
use panel::PanelHeader;
|
||||
use project::git::{GitEvent, Repository};
|
||||
use project::{Fs, Project, ProjectPath};
|
||||
|
@ -1007,19 +1008,19 @@ impl GitPanel {
|
|||
};
|
||||
if status_entry.status.is_created() {
|
||||
self.new_count += 1;
|
||||
if self.entry_appears_staged(status_entry) != Some(false) {
|
||||
if self.entry_is_staged(status_entry) != Some(false) {
|
||||
self.new_staged_count += 1;
|
||||
}
|
||||
} else {
|
||||
self.tracked_count += 1;
|
||||
if self.entry_appears_staged(status_entry) != Some(false) {
|
||||
if self.entry_is_staged(status_entry) != Some(false) {
|
||||
self.tracked_staged_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn entry_appears_staged(&self, entry: &GitStatusEntry) -> Option<bool> {
|
||||
fn entry_is_staged(&self, entry: &GitStatusEntry) -> Option<bool> {
|
||||
for pending in self.pending.iter().rev() {
|
||||
if pending.repo_paths.contains(&entry.repo_path) {
|
||||
return Some(pending.will_become_staged);
|
||||
|
@ -1301,6 +1302,49 @@ impl GitPanel {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn render_buffer_header_controls(
|
||||
&self,
|
||||
entity: &Entity<Self>,
|
||||
file: &Arc<dyn File>,
|
||||
_: &Window,
|
||||
cx: &App,
|
||||
) -> Option<AnyElement> {
|
||||
let repo = self.active_repository.as_ref()?.read(cx);
|
||||
let repo_path = repo.worktree_id_path_to_repo_path(file.worktree_id(cx), file.path())?;
|
||||
let ix = self.entries_by_path.get(&repo_path)?;
|
||||
let entry = self.entries.get(*ix)?;
|
||||
|
||||
let is_staged = self.entry_is_staged(entry.status_entry()?);
|
||||
|
||||
let checkbox = Checkbox::new("stage-file", is_staged.into())
|
||||
.disabled(!self.has_write_access(cx))
|
||||
.fill()
|
||||
.elevation(ElevationIndex::Surface)
|
||||
.on_click({
|
||||
let entry = entry.clone();
|
||||
let git_panel = entity.downgrade();
|
||||
move |_, window, cx| {
|
||||
git_panel
|
||||
.update(cx, |this, cx| {
|
||||
this.toggle_staged_for_entry(&entry, window, cx);
|
||||
cx.stop_propagation();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
});
|
||||
Some(
|
||||
h_flex()
|
||||
.id("start-slot")
|
||||
.child(checkbox)
|
||||
.child(git_status_icon(entry.status_entry()?.status, cx))
|
||||
.on_mouse_down(MouseButton::Left, |_, _, cx| {
|
||||
// prevent the list item active state triggering when toggling checkbox
|
||||
cx.stop_propagation();
|
||||
})
|
||||
.into_any_element(),
|
||||
)
|
||||
}
|
||||
|
||||
fn render_entries(
|
||||
&self,
|
||||
has_write_access: bool,
|
||||
|
@ -1473,14 +1517,6 @@ impl GitPanel {
|
|||
.map(|name| name.to_string_lossy().into_owned())
|
||||
.unwrap_or_else(|| entry.repo_path.to_string_lossy().into_owned());
|
||||
|
||||
let pending = self.pending.iter().rev().find_map(|pending| {
|
||||
if pending.repo_paths.contains(&entry.repo_path) {
|
||||
Some(pending.will_become_staged)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let repo_path = entry.repo_path.clone();
|
||||
let selected = self.selected_entry == Some(ix);
|
||||
let status_style = GitPanelSettings::get_global(cx).status_style;
|
||||
|
@ -1512,10 +1548,7 @@ impl GitPanel {
|
|||
|
||||
let id: ElementId = ElementId::Name(format!("entry_{}", display_name).into());
|
||||
|
||||
let mut is_staged = pending
|
||||
.or_else(|| entry.is_staged)
|
||||
.map(ToggleState::from)
|
||||
.unwrap_or(ToggleState::Indeterminate);
|
||||
let mut is_staged: ToggleState = self.entry_is_staged(entry).into();
|
||||
|
||||
if !self.has_staged_changes() && !entry.status.is_created() {
|
||||
is_staged = ToggleState::Selected;
|
||||
|
@ -1597,6 +1630,16 @@ impl GitPanel {
|
|||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn has_write_access(&self, cx: &App) -> bool {
|
||||
let room = self
|
||||
.workspace
|
||||
.upgrade()
|
||||
.and_then(|workspace| workspace.read(cx).active_call()?.read(cx).room().cloned());
|
||||
|
||||
room.as_ref()
|
||||
.map_or(true, |room| room.read(cx).local_participant().can_write())
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for GitPanel {
|
||||
|
@ -1734,6 +1777,28 @@ impl EventEmitter<Event> for GitPanel {}
|
|||
|
||||
impl EventEmitter<PanelEvent> for GitPanel {}
|
||||
|
||||
pub(crate) struct GitPanelAddon {
|
||||
pub(crate) git_panel: Entity<GitPanel>,
|
||||
}
|
||||
|
||||
impl editor::Addon for GitPanelAddon {
|
||||
fn to_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn render_buffer_header_controls(
|
||||
&self,
|
||||
excerpt_info: &ExcerptInfo,
|
||||
window: &Window,
|
||||
cx: &App,
|
||||
) -> Option<AnyElement> {
|
||||
let file = excerpt_info.buffer.file()?;
|
||||
let git_panel = self.git_panel.read(cx);
|
||||
|
||||
git_panel.render_buffer_header_controls(&self.git_panel, &file, window, cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Panel for GitPanel {
|
||||
fn persistent_name() -> &'static str {
|
||||
"GitPanel"
|
||||
|
|
|
@ -21,7 +21,7 @@ use workspace::{
|
|||
ItemNavHistory, ToolbarItemLocation, Workspace,
|
||||
};
|
||||
|
||||
use crate::git_panel::{GitPanel, GitStatusEntry};
|
||||
use crate::git_panel::{GitPanel, GitPanelAddon, GitStatusEntry};
|
||||
|
||||
actions!(git, [Diff]);
|
||||
|
||||
|
@ -29,6 +29,7 @@ pub(crate) struct ProjectDiff {
|
|||
multibuffer: Entity<MultiBuffer>,
|
||||
editor: Entity<Editor>,
|
||||
project: Entity<Project>,
|
||||
git_panel: Entity<GitPanel>,
|
||||
git_state: Entity<GitState>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
focus_handle: FocusHandle,
|
||||
|
@ -79,9 +80,16 @@ impl ProjectDiff {
|
|||
workspace.activate_item(&existing, true, true, window, cx);
|
||||
existing
|
||||
} else {
|
||||
let workspace_handle = cx.entity().downgrade();
|
||||
let project_diff =
|
||||
cx.new(|cx| Self::new(workspace.project().clone(), workspace_handle, window, cx));
|
||||
let workspace_handle = cx.entity();
|
||||
let project_diff = cx.new(|cx| {
|
||||
Self::new(
|
||||
workspace.project().clone(),
|
||||
workspace_handle,
|
||||
workspace.panel::<GitPanel>(cx).unwrap(),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
workspace.add_item_to_active_pane(
|
||||
Box::new(project_diff.clone()),
|
||||
None,
|
||||
|
@ -100,7 +108,8 @@ impl ProjectDiff {
|
|||
|
||||
fn new(
|
||||
project: Entity<Project>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
workspace: Entity<Workspace>,
|
||||
git_panel: Entity<GitPanel>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
|
@ -116,6 +125,9 @@ impl ProjectDiff {
|
|||
cx,
|
||||
);
|
||||
diff_display_editor.set_expand_all_diff_hunks(cx);
|
||||
diff_display_editor.register_addon(GitPanelAddon {
|
||||
git_panel: git_panel.clone(),
|
||||
});
|
||||
diff_display_editor
|
||||
});
|
||||
cx.subscribe_in(&editor, window, Self::handle_editor_event)
|
||||
|
@ -141,7 +153,8 @@ impl ProjectDiff {
|
|||
Self {
|
||||
project,
|
||||
git_state: git_state.clone(),
|
||||
workspace,
|
||||
git_panel: git_panel.clone(),
|
||||
workspace: workspace.downgrade(),
|
||||
focus_handle,
|
||||
editor,
|
||||
multibuffer,
|
||||
|
@ -423,9 +436,16 @@ impl Item for ProjectDiff {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Some(
|
||||
cx.new(|cx| ProjectDiff::new(self.project.clone(), self.workspace.clone(), window, cx)),
|
||||
)
|
||||
let workspace = self.workspace.upgrade()?;
|
||||
Some(cx.new(|cx| {
|
||||
ProjectDiff::new(
|
||||
self.project.clone(),
|
||||
workspace,
|
||||
self.git_panel.clone(),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}))
|
||||
}
|
||||
|
||||
fn is_dirty(&self, cx: &App) -> bool {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue