diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 0bcec87de3f4c8df451d015373bfdb0ac24ad59a..fd18f6e7bf6b5835ba762913520706bf10538076 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -27,11 +27,12 @@ use git::status::StageStatus; use git::{Amend, ToggleStaged, repository::RepoPath, status::FileStatus}; use git::{ExpandCommitEditor, RestoreTrackedFiles, StageAll, TrashUntrackedFiles, UnstageAll}; use gpui::{ - Action, Animation, AnimationExt as _, Axis, ClickEvent, Corner, DismissEvent, Entity, - EventEmitter, FocusHandle, Focusable, KeyContext, ListHorizontalSizingBehavior, - ListSizingBehavior, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, Point, - PromptLevel, ScrollStrategy, Subscription, Task, Transformation, UniformListScrollHandle, - WeakEntity, actions, anchored, deferred, percentage, uniform_list, + Action, Animation, AnimationExt as _, AsyncWindowContext, Axis, ClickEvent, Corner, + DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, KeyContext, + ListHorizontalSizingBehavior, ListSizingBehavior, Modifiers, ModifiersChangedEvent, + MouseButton, MouseDownEvent, Point, PromptLevel, ScrollStrategy, Subscription, Task, + Transformation, UniformListScrollHandle, WeakEntity, actions, anchored, deferred, percentage, + uniform_list, }; use itertools::Itertools; use language::{Buffer, File}; @@ -63,7 +64,7 @@ use ui::{ Tooltip, prelude::*, }; use util::{ResultExt, TryFutureExt, maybe}; -use workspace::AppState; + use workspace::{ Workspace, dock::{DockPosition, Panel, PanelEvent}, @@ -389,144 +390,148 @@ pub(crate) fn commit_message_editor( } impl GitPanel { - pub fn new( - workspace: Entity, - project: Entity, - app_state: Arc, + fn new( + workspace: &mut Workspace, window: &mut Window, - cx: &mut Context, - ) -> Self { + cx: &mut Context, + ) -> Entity { + let project = workspace.project().clone(); + let app_state = workspace.app_state().clone(); let fs = app_state.fs.clone(); let git_store = project.read(cx).git_store().clone(); let active_repository = project.read(cx).active_repository(cx); - let workspace = workspace.downgrade(); - let focus_handle = cx.focus_handle(); - cx.on_focus(&focus_handle, window, Self::focus_in).detach(); - cx.on_focus_out(&focus_handle, window, |this, _, window, cx| { - this.hide_scrollbars(window, cx); - }) - .detach(); + let git_panel = cx.new(|cx| { + let focus_handle = cx.focus_handle(); + cx.on_focus(&focus_handle, window, Self::focus_in).detach(); + cx.on_focus_out(&focus_handle, window, |this, _, window, cx| { + this.hide_scrollbars(window, cx); + }) + .detach(); - let mut was_sort_by_path = GitPanelSettings::get_global(cx).sort_by_path; - cx.observe_global::(move |this, cx| { - let is_sort_by_path = GitPanelSettings::get_global(cx).sort_by_path; - if is_sort_by_path != was_sort_by_path { - this.update_visible_entries(cx); - } - was_sort_by_path = is_sort_by_path - }) - .detach(); + let mut was_sort_by_path = GitPanelSettings::get_global(cx).sort_by_path; + cx.observe_global::(move |this, cx| { + let is_sort_by_path = GitPanelSettings::get_global(cx).sort_by_path; + if is_sort_by_path != was_sort_by_path { + this.update_visible_entries(cx); + } + was_sort_by_path = is_sort_by_path + }) + .detach(); - // just to let us render a placeholder editor. - // Once the active git repo is set, this buffer will be replaced. - let temporary_buffer = cx.new(|cx| Buffer::local("", cx)); - let commit_editor = cx.new(|cx| { - commit_message_editor(temporary_buffer, None, project.clone(), true, window, cx) - }); + // just to let us render a placeholder editor. + // Once the active git repo is set, this buffer will be replaced. + let temporary_buffer = cx.new(|cx| Buffer::local("", cx)); + let commit_editor = cx.new(|cx| { + commit_message_editor(temporary_buffer, None, project.clone(), true, window, cx) + }); - commit_editor.update(cx, |editor, cx| { - editor.clear(window, cx); - }); + commit_editor.update(cx, |editor, cx| { + editor.clear(window, cx); + }); - let scroll_handle = UniformListScrollHandle::new(); + let scroll_handle = UniformListScrollHandle::new(); - cx.subscribe_in( - &git_store, - window, - move |this, git_store, event, window, cx| match event { - GitStoreEvent::ActiveRepositoryChanged(_) => { - this.active_repository = git_store.read(cx).active_repository(); - this.schedule_update(true, window, cx); - } - GitStoreEvent::RepositoryUpdated( - _, - RepositoryEvent::Updated { full_scan }, - true, - ) => { - this.schedule_update(*full_scan, window, cx); - } + let vertical_scrollbar = ScrollbarProperties { + axis: Axis::Vertical, + state: ScrollbarState::new(scroll_handle.clone()).parent_entity(&cx.entity()), + show_scrollbar: false, + show_track: false, + auto_hide: false, + hide_task: None, + }; - GitStoreEvent::RepositoryAdded(_) | GitStoreEvent::RepositoryRemoved(_) => { - this.schedule_update(false, window, cx); - } - GitStoreEvent::IndexWriteError(error) => { - this.workspace - .update(cx, |workspace, cx| { - workspace.show_error(error, cx); - }) - .ok(); + let horizontal_scrollbar = ScrollbarProperties { + axis: Axis::Horizontal, + state: ScrollbarState::new(scroll_handle.clone()).parent_entity(&cx.entity()), + show_scrollbar: false, + show_track: false, + auto_hide: false, + hide_task: None, + }; + + let mut assistant_enabled = AgentSettings::get_global(cx).enabled; + let _settings_subscription = cx.observe_global::(move |_, cx| { + if assistant_enabled != AgentSettings::get_global(cx).enabled { + assistant_enabled = AgentSettings::get_global(cx).enabled; + cx.notify(); } - GitStoreEvent::RepositoryUpdated(_, _, _) => {} - GitStoreEvent::JobsUpdated | GitStoreEvent::ConflictsUpdated => {} - }, - ) - .detach(); + }); - let vertical_scrollbar = ScrollbarProperties { - axis: Axis::Vertical, - state: ScrollbarState::new(scroll_handle.clone()).parent_entity(&cx.entity()), - show_scrollbar: false, - show_track: false, - auto_hide: false, - hide_task: None, - }; + cx.subscribe_in( + &git_store, + window, + move |this, _git_store, event, window, cx| match event { + GitStoreEvent::ActiveRepositoryChanged(_) => { + this.active_repository = this.project.read(cx).active_repository(cx); + this.schedule_update(true, window, cx); + } + GitStoreEvent::RepositoryUpdated( + _, + RepositoryEvent::Updated { full_scan }, + true, + ) => { + this.schedule_update(*full_scan, window, cx); + } - let horizontal_scrollbar = ScrollbarProperties { - axis: Axis::Horizontal, - state: ScrollbarState::new(scroll_handle.clone()).parent_entity(&cx.entity()), - show_scrollbar: false, - show_track: false, - auto_hide: false, - hide_task: None, - }; + GitStoreEvent::RepositoryAdded(_) | GitStoreEvent::RepositoryRemoved(_) => { + this.schedule_update(false, window, cx); + } + GitStoreEvent::IndexWriteError(error) => { + this.workspace + .update(cx, |workspace, cx| { + workspace.show_error(error, cx); + }) + .ok(); + } + GitStoreEvent::RepositoryUpdated(_, _, _) => {} + GitStoreEvent::JobsUpdated | GitStoreEvent::ConflictsUpdated => {} + }, + ) + .detach(); - let mut assistant_enabled = AgentSettings::get_global(cx).enabled; - let _settings_subscription = cx.observe_global::(move |_, cx| { - if assistant_enabled != AgentSettings::get_global(cx).enabled { - assistant_enabled = AgentSettings::get_global(cx).enabled; - cx.notify(); - } + let mut this = Self { + active_repository, + commit_editor, + conflicted_count: 0, + conflicted_staged_count: 0, + current_modifiers: window.modifiers(), + add_coauthors: true, + generate_commit_message_task: None, + entries: Vec::new(), + focus_handle: cx.focus_handle(), + fs, + new_count: 0, + new_staged_count: 0, + pending: Vec::new(), + pending_commit: None, + amend_pending: false, + pending_serialization: Task::ready(None), + single_staged_entry: None, + single_tracked_entry: None, + project, + scroll_handle, + max_width_item_index: None, + selected_entry: None, + marked_entries: Vec::new(), + tracked_count: 0, + tracked_staged_count: 0, + update_visible_entries_task: Task::ready(()), + width: None, + show_placeholders: false, + context_menu: None, + workspace: workspace.weak_handle(), + modal_open: false, + entry_count: 0, + horizontal_scrollbar, + vertical_scrollbar, + _settings_subscription, + }; + + this.schedule_update(false, window, cx); + this }); - let mut git_panel = Self { - active_repository, - commit_editor, - conflicted_count: 0, - conflicted_staged_count: 0, - current_modifiers: window.modifiers(), - add_coauthors: true, - generate_commit_message_task: None, - entries: Vec::new(), - focus_handle: cx.focus_handle(), - fs, - new_count: 0, - new_staged_count: 0, - pending: Vec::new(), - pending_commit: None, - amend_pending: false, - pending_serialization: Task::ready(None), - single_staged_entry: None, - single_tracked_entry: None, - project, - scroll_handle, - max_width_item_index: None, - selected_entry: None, - marked_entries: Vec::new(), - tracked_count: 0, - tracked_staged_count: 0, - update_visible_entries_task: Task::ready(()), - width: None, - show_placeholders: false, - context_menu: None, - workspace, - modal_open: false, - entry_count: 0, - horizontal_scrollbar, - vertical_scrollbar, - _settings_subscription, - }; - git_panel.schedule_update(false, window, cx); git_panel } @@ -4141,6 +4146,32 @@ impl GitPanel { self.amend_pending = value; cx.notify(); } + + pub async fn load( + workspace: WeakEntity, + mut cx: AsyncWindowContext, + ) -> anyhow::Result> { + let serialized_panel = cx + .background_spawn(async move { KEY_VALUE_STORE.read_kvp(&GIT_PANEL_KEY) }) + .await + .context("loading git panel") + .log_err() + .flatten() + .and_then(|panel| serde_json::from_str::(&panel).log_err()); + + workspace.update_in(&mut cx, |workspace, window, cx| { + let panel = GitPanel::new(workspace, window, cx); + + if let Some(serialized_panel) = serialized_panel { + panel.update(cx, |panel, cx| { + panel.width = serialized_panel.width; + cx.notify(); + }) + } + + panel + }) + } } fn current_language_model(cx: &Context<'_, GitPanel>) -> Option> { @@ -4852,7 +4883,7 @@ impl Component for PanelRepoFooter { #[cfg(test)] mod tests { use git::status::StatusCode; - use gpui::TestAppContext; + use gpui::{TestAppContext, VisualTestContext}; use project::{FakeFs, WorktreeSettings}; use serde_json::json; use settings::SettingsStore; @@ -4916,8 +4947,9 @@ mod tests { let project = Project::test(fs.clone(), [path!("/root/zed/crates/gpui").as_ref()], cx).await; - let (workspace, cx) = - cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx)); + let workspace = + cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx)); + let cx = &mut VisualTestContext::from_window(*workspace, cx); cx.read(|cx| { project @@ -4934,10 +4966,7 @@ mod tests { cx.executor().run_until_parked(); - let app_state = workspace.read_with(cx, |workspace, _| workspace.app_state().clone()); - let panel = cx.new_window_entity(|window, cx| { - GitPanel::new(workspace.clone(), project.clone(), app_state, window, cx) - }); + let panel = workspace.update(cx, GitPanel::new).unwrap(); let handle = cx.update_window_entity(&panel, |panel, _, _| { std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(())) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 22a03ea9bc15e8f147b6a77240d50b743a7982bd..c9784d6f15e3b9fa282dfc53093d547cb29cbd5c 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -472,6 +472,7 @@ fn initialize_panels( let project_panel = ProjectPanel::load(workspace_handle.clone(), cx.clone()); let outline_panel = OutlinePanel::load(workspace_handle.clone(), cx.clone()); let terminal_panel = TerminalPanel::load(workspace_handle.clone(), cx.clone()); + let git_panel = GitPanel::load(workspace_handle.clone(), cx.clone()); let channels_panel = collab_ui::collab_panel::CollabPanel::load(workspace_handle.clone(), cx.clone()); let chat_panel = @@ -485,12 +486,14 @@ fn initialize_panels( project_panel, outline_panel, terminal_panel, + git_panel, channels_panel, chat_panel, notification_panel, ) = futures::try_join!( project_panel, outline_panel, + git_panel, terminal_panel, channels_panel, chat_panel, @@ -501,6 +504,7 @@ fn initialize_panels( workspace.add_panel(project_panel, window, cx); workspace.add_panel(outline_panel, window, cx); workspace.add_panel(terminal_panel, window, cx); + workspace.add_panel(git_panel, window, cx); workspace.add_panel(channels_panel, window, cx); workspace.add_panel(chat_panel, window, cx); workspace.add_panel(notification_panel, window, cx); @@ -518,12 +522,6 @@ fn initialize_panels( ) .detach() }); - - let entity = cx.entity(); - let project = workspace.project().clone(); - let app_state = workspace.app_state().clone(); - let git_panel = cx.new(|cx| GitPanel::new(entity, project, app_state, window, cx)); - workspace.add_panel(git_panel, window, cx); })?; let is_assistant2_enabled = !cfg!(test);