diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index a72cd74359..ba7f514766 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -1071,6 +1071,8 @@ "ctrl-shift-enter": "git::Amend", "alt-up": "git_panel::FocusChanges", "alt-l": "git::GenerateCommitMessage", + "shift-escape": "git::ExpandCommitEditor", + "alt-shift-escape": "git::ToggleFillCommitEditor", }, }, { diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 4f26eeeb8b..11750aa741 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -1102,6 +1102,7 @@ "shift-tab": "git_panel::FocusChanges", "alt-up": "git_panel::FocusChanges", "shift-escape": "git::ExpandCommitEditor", + "alt-shift-escape": "git::ToggleFillCommitEditor", "alt-tab": "git::GenerateCommitMessage", }, }, diff --git a/assets/keymaps/default-windows.json b/assets/keymaps/default-windows.json index 8d60a68dbc..2526a9412c 100644 --- a/assets/keymaps/default-windows.json +++ b/assets/keymaps/default-windows.json @@ -1069,6 +1069,8 @@ "ctrl-shift-enter": "git::Amend", "alt-up": "git_panel::FocusChanges", "alt-l": "git::GenerateCommitMessage", + "shift-escape": "git::ExpandCommitEditor", + "alt-shift-escape": "git::ToggleFillCommitEditor", }, }, { diff --git a/crates/git/src/git.rs b/crates/git/src/git.rs index debb7649ab..d5274d24b5 100644 --- a/crates/git/src/git.rs +++ b/crates/git/src/git.rs @@ -94,6 +94,9 @@ actions!( Cancel, /// Expands the commit message editor. ExpandCommitEditor, + /// Toggles whether the commit message editor fills all the available + /// vertical space within the git panel. + ToggleFillCommitEditor, /// Generates a commit message using AI. GenerateCommitMessage, /// Initializes a new git repository. diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 62f8edcfbd..f0900b56bc 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -16,7 +16,7 @@ use askpass::AskPassDelegate; use collections::{BTreeMap, HashMap, HashSet}; use db::kvp::KeyValueStore; use editor::{ - Direction, Editor, EditorElement, EditorMode, MultiBuffer, MultiBufferOffset, + Direction, Editor, EditorElement, EditorMode, MultiBuffer, MultiBufferOffset, SizingBehavior, actions::ExpandAllDiffHunks, }; use editor::{EditorStyle, RewrapOptions}; @@ -34,7 +34,7 @@ use git::status::{DiffStat, StageStatus}; use git::{Amend, Signoff, ToggleStaged, repository::RepoPath, status::FileStatus}; use git::{ ExpandCommitEditor, GitHostingProviderRegistry, RestoreTrackedFiles, StageAll, StashAll, - StashApply, StashPop, TrashUntrackedFiles, UnstageAll, + StashApply, StashPop, ToggleFillCommitEditor, TrashUntrackedFiles, UnstageAll, }; use gpui::{ Action, Anchor, AsyncApp, AsyncWindowContext, Bounds, ClickEvent, DismissEvent, Empty, Entity, @@ -247,6 +247,13 @@ pub fn register(workspace: &mut Workspace) { workspace.register_action(|workspace, _: &ExpandCommitEditor, window, cx| { CommitModal::toggle(workspace, None, window, cx) }); + workspace.register_action(|workspace, _: &ToggleFillCommitEditor, window, cx| { + if let Some(panel) = workspace.panel::(cx) { + panel.update(cx, |panel, cx| { + panel.toggle_fill_commit_editor(&Default::default(), window, cx) + }); + } + }); workspace.register_action(|workspace, _: &git::Init, window, cx| { if let Some(panel) = workspace.panel::(cx) { panel.update(cx, |panel, cx| panel.git_init(window, cx)); @@ -619,6 +626,8 @@ impl TruncatedPatch { pub struct GitPanel { pub(crate) active_repository: Option>, pub(crate) commit_editor: Entity, + /// Whether the commit editor should fill the vertical height of the panel. + commit_editor_expanded: bool, conflicted_count: usize, conflicted_staged_count: usize, add_coauthors: bool, @@ -809,6 +818,7 @@ impl GitPanel { let mut this = Self { active_repository, commit_editor, + commit_editor_expanded: false, conflicted_count: 0, conflicted_staged_count: 0, add_coauthors: true, @@ -4259,9 +4269,34 @@ impl GitPanel { } } + fn toggle_fill_commit_editor( + &mut self, + _: &ToggleFillCommitEditor, + _window: &mut Window, + cx: &mut Context, + ) { + self.commit_editor_expanded = !self.commit_editor_expanded; + self.commit_editor.update(cx, |editor, _cx| { + if self.commit_editor_expanded { + editor.set_mode(EditorMode::Full { + scale_ui_elements_with_buffer_font_size: false, + show_active_line_background: false, + sizing_behavior: SizingBehavior::ExcludeOverscrollMargin, + }) + } else { + editor.set_mode(EditorMode::AutoHeight { + min_lines: MAX_PANEL_EDITOR_LINES, + max_lines: Some(MAX_PANEL_EDITOR_LINES), + }) + } + }); + + cx.notify(); + } + fn expand_commit_editor( &mut self, - _: &git::ExpandCommitEditor, + _: &ExpandCommitEditor, window: &mut Window, cx: &mut Context, ) { @@ -4375,10 +4410,7 @@ impl GitPanel { let active_repository = self.active_repository.clone()?; let panel_editor_style = panel_editor_style(true, window, cx); let enable_coauthors = self.render_co_authors(cx); - let editor_focus_handle = self.commit_editor.focus_handle(cx); - let expand_tooltip_focus_handle = editor_focus_handle; - let branch = active_repository.read(cx).branch.clone(); let head_commit = active_repository.read(cx).head_commit.clone(); @@ -4414,6 +4446,7 @@ impl GitPanel { }; let footer = v_flex() + .when(self.commit_editor_expanded, |this| this.flex_1().min_h_0()) .child(PanelRepoFooter::new( display_name, branch, @@ -4448,7 +4481,10 @@ impl GitPanel { .cursor_text() .relative() .w_full() - .h(max_height + footer_size) + .when(self.commit_editor_expanded, |this| this.flex_1().min_h_0()) + .when(!self.commit_editor_expanded, |this| { + this.h(max_height + footer_size) + }) .border_t_1() .border_color(if title_exceeds_limit { cx.theme().status().warning_border @@ -4486,6 +4522,9 @@ impl GitPanel { ) .child( div() + .when(self.commit_editor_expanded, |this| { + this.flex_1().min_h_0().pb(footer_size) + }) .pr_2p5() .on_action(|&zed_actions::editor::MoveUp, _, cx| { cx.stop_propagation(); @@ -4500,19 +4539,21 @@ impl GitPanel { .absolute() .top_2() .right_2() - .opacity(0.5) - .hover(|this| this.opacity(1.0)) + .gap_px() + .opacity(0.6) + .hover(|s| s.opacity(1.0)) .child( - panel_icon_button("expand-commit-editor", IconName::Maximize) + panel_icon_button("expand-commit-editor", IconName::MaximizeAlt) .icon_size(IconSize::Small) - .size(ui::ButtonSize::Default) - .tooltip(move |_window, cx| { - Tooltip::for_action_in( - "Open Commit Modal", - &git::ExpandCommitEditor, - &expand_tooltip_focus_handle, - cx, - ) + .tooltip({ + move |_window, cx| { + Tooltip::for_action_in( + "Open Commit Modal", + &git::ExpandCommitEditor, + &editor_focus_handle, + cx, + ) + } }) .on_click(cx.listener({ move |_, _, window, cx| { @@ -4522,7 +4563,36 @@ impl GitPanel { ) } })), - ), + ) + .child({ + let (icon, label) = if self.commit_editor_expanded { + (IconName::Minimize, "Collapse Commit Editor") + } else { + (IconName::Maximize, "Expand Commit Editor") + }; + let focus_handle = self.focus_handle.clone(); + + panel_icon_button("fill-commit-editor", icon) + .icon_size(IconSize::Small) + .tooltip({ + move |_window, cx| { + Tooltip::for_action_in( + label, + &git::ToggleFillCommitEditor, + &focus_handle, + cx, + ) + } + }) + .on_click(cx.listener({ + move |_, _, window, cx| { + window.dispatch_action( + git::ToggleFillCommitEditor.boxed_clone(), + cx, + ) + } + })) + }), ), ); @@ -5932,15 +6002,22 @@ impl Render for GitPanel { .child( v_flex() .size_full() - .children(self.render_panel_header(window, cx)) - .map(|this| { - if let Some(repo) = self.active_repository.clone() - && has_entries - { - this.child(self.render_entries(has_write_access, repo, window, cx)) - } else { - this.child(self.render_empty_state(cx).into_any_element()) - } + .when(!self.commit_editor_expanded, |this| { + this.children(self.render_panel_header(window, cx)) + .map(|this| { + if let Some(repo) = self.active_repository.clone() + && has_entries + { + this.child(self.render_entries( + has_write_access, + repo, + window, + cx, + )) + } else { + this.child(self.render_empty_state(cx).into_any_element()) + } + }) }) .children(self.render_footer(window, cx)) .when(self.amend_pending, |this| { @@ -8275,4 +8352,48 @@ mod tests { ); }); } + + #[gpui::test] + async fn test_fill_commit_editor_toggle(cx: &mut TestAppContext) { + init_test(cx); + let fs = FakeFs::new(cx.background_executor.clone()); + fs.insert_tree( + "/root", + json!({ "project": { ".git": {}, "src": { "main.rs": "fn main() {}" } } }), + ) + .await; + + let project = Project::test(fs.clone(), [Path::new(path!("/root/project"))], cx).await; + let window_handle = + cx.add_window(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx)); + let workspace = window_handle + .read_with(cx, |mw, _| mw.workspace().clone()) + .unwrap(); + let cx = &mut VisualTestContext::from_window(window_handle.into(), cx); + cx.executor().run_until_parked(); + + let panel = workspace.update_in(cx, GitPanel::new); + + panel.update_in(cx, |panel, window, cx| { + assert!(!panel.commit_editor_expanded); + assert!(matches!( + panel.commit_editor.read(cx).mode().clone(), + EditorMode::AutoHeight { .. } + )); + + panel.toggle_fill_commit_editor(&ToggleFillCommitEditor, window, cx); + assert!(panel.commit_editor_expanded); + assert!(matches!( + panel.commit_editor.read(cx).mode().clone(), + EditorMode::Full { .. } + )); + + panel.toggle_fill_commit_editor(&ToggleFillCommitEditor, window, cx); + assert!(!panel.commit_editor_expanded); + assert!(matches!( + panel.commit_editor.read(cx).mode().clone(), + EditorMode::AutoHeight { .. } + )); + }); + } }