git_panel: Persist dock size (#32111)
Closes #32054 The dock size for the git panel wasn't being persisted across Zed restarts. This was because the git panel lacked the serialization pattern used by other panels. Please let me know if you have any sort of feedback or anything, as i'm still trying to learn :] Release Notes: - Fixed Git Panel dock size not being remembered across Zed restarts ## TODO - [x] Update/fix tests that may be broken by the GitPanel constructor changes
This commit is contained in:
parent
387281fa5b
commit
0cb7dd2972
2 changed files with 175 additions and 148 deletions
|
@ -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<Workspace>,
|
||||
project: Entity<Project>,
|
||||
app_state: Arc<AppState>,
|
||||
fn new(
|
||||
workspace: &mut Workspace,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
cx: &mut Context<Workspace>,
|
||||
) -> Entity<Self> {
|
||||
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::<SettingsStore>(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::<SettingsStore>(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);
|
||||
});
|
||||
|
||||
let scroll_handle = UniformListScrollHandle::new();
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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::<SettingsStore>(move |_, cx| {
|
||||
if assistant_enabled != AgentSettings::get_global(cx).enabled {
|
||||
assistant_enabled = AgentSettings::get_global(cx).enabled;
|
||||
cx.notify();
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 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
|
||||
});
|
||||
|
||||
commit_editor.update(cx, |editor, cx| {
|
||||
editor.clear(window, cx);
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 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,
|
||||
};
|
||||
|
||||
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::<SettingsStore>(move |_, cx| {
|
||||
if assistant_enabled != AgentSettings::get_global(cx).enabled {
|
||||
assistant_enabled = AgentSettings::get_global(cx).enabled;
|
||||
cx.notify();
|
||||
}
|
||||
});
|
||||
|
||||
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<Workspace>,
|
||||
mut cx: AsyncWindowContext,
|
||||
) -> anyhow::Result<Entity<Self>> {
|
||||
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::<SerializedGitPanel>(&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<Arc<dyn LanguageModel>> {
|
||||
|
@ -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(()))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue