From 54421b11f33ad4d27e49950da776025c0a608946 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 18 May 2023 10:58:24 -0700 Subject: [PATCH 1/5] wip --- crates/language/src/buffer.rs | 18 +++++++++++++++- crates/project/src/project.rs | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 5539d1d941..93955a2474 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -682,6 +682,20 @@ impl Buffer { self.git_diff_status.diff.needs_update(self) } + fn git_diff_recalc_2(&mut self, cx: &mut ModelContext) -> Option> { + let diff_base = &self.diff_base?; + let snapshot = self.snapshot(); + let handle = cx.weak_handle(); + + let mut diff = self.git_diff_status.diff.clone(); + Some(cx.background().spawn(async move { + diff.update(&diff_base, &snapshot).await; + if let Some(this) = handle.upgrade(cx) { + // this.update(cx) + } + })) + } + pub fn git_diff_recalc(&mut self, cx: &mut ModelContext) { if self.git_diff_status.update_in_progress { self.git_diff_status.update_requested = true; @@ -689,6 +703,7 @@ impl Buffer { } if let Some(diff_base) = &self.diff_base { + self.git_diff_status.update_in_progress = true; let snapshot = self.snapshot(); let diff_base = diff_base.clone(); @@ -706,9 +721,10 @@ impl Buffer { this.git_diff_update_count += 1; cx.notify(); - this.git_diff_status.update_in_progress = false; if this.git_diff_status.update_requested { this.git_diff_recalc(cx); + } else { + this.git_diff_status.update_in_progress = false; } }) } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 391a698a1b..f93d7d4b50 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -130,6 +130,7 @@ pub struct Project { incomplete_remote_buffers: HashMap>>, buffer_snapshots: HashMap>>, // buffer_id -> server_id -> vec of snapshots buffers_being_formatted: HashSet, + buffers_needing_diff: HashSet>, nonce: u128, _maintain_buffer_languages: Task<()>, _maintain_workspace_config: Task<()>, @@ -484,6 +485,7 @@ impl Project { language_server_statuses: Default::default(), last_workspace_edits_by_language_server: Default::default(), buffers_being_formatted: Default::default(), + buffers_needing_diff: Default::default(), nonce: StdRng::from_entropy().gen(), terminals: Terminals { local_handles: Vec::new(), @@ -573,6 +575,7 @@ impl Project { last_workspace_edits_by_language_server: Default::default(), opened_buffers: Default::default(), buffers_being_formatted: Default::default(), + buffers_needing_diff: Default::default(), buffer_snapshots: Default::default(), nonce: StdRng::from_entropy().gen(), terminals: Terminals { @@ -1924,6 +1927,20 @@ impl Project { event: &BufferEvent, cx: &mut ModelContext, ) -> Option<()> { + if matches!(event, BufferEvent::Edited { .. } | BufferEvent::Reloaded) { + self.buffers_needing_diff.insert(buffer.downgrade()); + if self.buffers_needing_diff.len() == 1 { + let this = cx.weak_handle(); + cx.defer(move |cx| { + if let Some(this) = this.upgrade(cx) { + this.update(cx, |this, cx| { + this.recalculate_buffer_diffs(cx); + }); + } + }); + } + } + match event { BufferEvent::Operation(operation) => { self.buffer_ordered_messages_tx @@ -2063,6 +2080,29 @@ impl Project { None } + fn recalculate_buffer_diffs(&mut self, cx: &mut ModelContext) { + cx.spawn(|this, mut cx| async move { + let tasks: Vec<_> = this.update(&mut cx, |this, cx| { + this.buffers_needing_diff + .drain() + .filter_map(|buffer| { + let buffer = buffer.upgrade(cx)?; + buffer.update(cx, |buffer, cx| buffer.git_diff_recalc_2(cx)) + }) + .collect() + }); + + let updates = futures::future::join_all(tasks).await; + + this.update(&mut cx, |this, cx| { + if !this.buffers_needing_diff.is_empty() { + this.recalculate_buffer_diffs(cx); + } + }); + }) + .detach(); + } + fn language_servers_for_worktree( &self, worktree_id: WorktreeId, From cede296b04d2717ca74fe212d89acef95c56a61e Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 18 May 2023 18:25:58 -0400 Subject: [PATCH 2/5] Project level git diff recalc handling This avoids an issue where in a many-buffer multi-buffer, each modified buffer could complete its recalc independently, causing a cascade of repeated notifies Now all recalcs started at the same time must complete before A: Starting another recalc pass B: The master notify occurring Each buffer can still show its new diff if something else triggers it to notify earlier, this is desirable and does not have the same negative effects as the notify cascade as those re-layouts would need to happen anyway Co-Authored-By: Max Brunsfeld --- crates/editor/src/multi_buffer.rs | 18 +++++----- crates/language/src/buffer.rs | 22 +++++++++---- crates/project/src/project.rs | 55 ++++++++++++++++++++++--------- crates/project/src/worktree.rs | 6 +--- 4 files changed, 64 insertions(+), 37 deletions(-) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 6b1ad6c5b2..e749f5dcfb 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -343,15 +343,15 @@ impl MultiBuffer { self.read(cx).symbols_containing(offset, theme) } - pub fn git_diff_recalc(&mut self, cx: &mut ModelContext) { - let buffers = self.buffers.borrow(); - for buffer_state in buffers.values() { - if buffer_state.buffer.read(cx).needs_git_diff_recalc() { - buffer_state - .buffer - .update(cx, |buffer, cx| buffer.git_diff_recalc(cx)) - } - } + pub fn git_diff_recalc(&mut self, _: &mut ModelContext) { + // let buffers = self.buffers.borrow(); + // for buffer_state in buffers.values() { + // if buffer_state.buffer.read(cx).needs_git_diff_recalc() { + // buffer_state + // .buffer + // .update(cx, |buffer, cx| buffer.git_diff_recalc(cx)) + // } + // } } pub fn edit( diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 93955a2474..f6eb2a5d2d 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -682,21 +682,29 @@ impl Buffer { self.git_diff_status.diff.needs_update(self) } - fn git_diff_recalc_2(&mut self, cx: &mut ModelContext) -> Option> { - let diff_base = &self.diff_base?; + pub fn git_diff_recalc_2(&mut self, cx: &mut ModelContext) -> Option> { + let diff_base = self.diff_base.clone()?; // TODO: Make this an Arc let snapshot = self.snapshot(); - let handle = cx.weak_handle(); let mut diff = self.git_diff_status.diff.clone(); - Some(cx.background().spawn(async move { + let diff = cx.background().spawn(async move { diff.update(&diff_base, &snapshot).await; - if let Some(this) = handle.upgrade(cx) { - // this.update(cx) + diff + }); + + let handle = cx.weak_handle(); + Some(cx.spawn_weak(|_, mut cx| async move { + let buffer_diff = diff.await; + if let Some(this) = handle.upgrade(&mut cx) { + this.update(&mut cx, |this, _| { + this.git_diff_status.diff = buffer_diff; + this.git_diff_update_count += 1; + }) } })) } - pub fn git_diff_recalc(&mut self, cx: &mut ModelContext) { + fn git_diff_recalc(&mut self, cx: &mut ModelContext) { if self.git_diff_status.update_in_progress { self.git_diff_status.update_requested = true; return; diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index f93d7d4b50..3f520c7e99 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1610,6 +1610,7 @@ impl Project { buffer: &ModelHandle, cx: &mut ModelContext, ) -> Result<()> { + self.request_buffer_diff_recalculation(buffer, cx); buffer.update(cx, |buffer, _| { buffer.set_language_registry(self.languages.clone()) }); @@ -1928,17 +1929,7 @@ impl Project { cx: &mut ModelContext, ) -> Option<()> { if matches!(event, BufferEvent::Edited { .. } | BufferEvent::Reloaded) { - self.buffers_needing_diff.insert(buffer.downgrade()); - if self.buffers_needing_diff.len() == 1 { - let this = cx.weak_handle(); - cx.defer(move |cx| { - if let Some(this) = this.upgrade(cx) { - this.update(cx, |this, cx| { - this.recalculate_buffer_diffs(cx); - }); - } - }); - } + self.request_buffer_diff_recalculation(&buffer, cx); } match event { @@ -2080,11 +2071,33 @@ impl Project { None } + fn request_buffer_diff_recalculation( + &mut self, + buffer: &ModelHandle, + cx: &mut ModelContext, + ) { + self.buffers_needing_diff.insert(buffer.downgrade()); + if self.buffers_needing_diff.len() == 1 { + let this = cx.weak_handle(); + cx.defer(move |cx| { + if let Some(this) = this.upgrade(cx) { + this.update(cx, |this, cx| { + this.recalculate_buffer_diffs(cx); + }); + } + }); + } + } + fn recalculate_buffer_diffs(&mut self, cx: &mut ModelContext) { cx.spawn(|this, mut cx| async move { - let tasks: Vec<_> = this.update(&mut cx, |this, cx| { - this.buffers_needing_diff - .drain() + let buffers: Vec<_> = this.update(&mut cx, |this, _| { + this.buffers_needing_diff.drain().collect() + }); + + let tasks: Vec<_> = this.update(&mut cx, |_, cx| { + buffers + .iter() .filter_map(|buffer| { let buffer = buffer.upgrade(cx)?; buffer.update(cx, |buffer, cx| buffer.git_diff_recalc_2(cx)) @@ -2092,11 +2105,18 @@ impl Project { .collect() }); - let updates = futures::future::join_all(tasks).await; + futures::future::join_all(tasks).await; this.update(&mut cx, |this, cx| { if !this.buffers_needing_diff.is_empty() { this.recalculate_buffer_diffs(cx); + } else { + // TODO: Would a `ModelContext.notify()` suffice here? + for buffer in buffers { + if let Some(buffer) = buffer.upgrade(cx) { + buffer.update(cx, |_, cx| cx.notify()); + } + } } }); }) @@ -6229,11 +6249,13 @@ impl Project { let Some(this) = this.upgrade(&cx) else { return Err(anyhow!("project dropped")); }; + let buffer = this.read_with(&cx, |this, cx| { this.opened_buffers .get(&id) .and_then(|buffer| buffer.upgrade(cx)) }); + if let Some(buffer) = buffer { break buffer; } else if this.read_with(&cx, |this, _| this.is_read_only()) { @@ -6244,12 +6266,13 @@ impl Project { this.incomplete_remote_buffers.entry(id).or_default(); }); drop(this); + opened_buffer_rx .next() .await .ok_or_else(|| anyhow!("project dropped while waiting for buffer"))?; }; - buffer.update(&mut cx, |buffer, cx| buffer.git_diff_recalc(cx)); + Ok(buffer) }) } diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index d2c035f916..3a7044de0c 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -719,11 +719,7 @@ impl LocalWorktree { .background() .spawn(async move { text::Buffer::new(0, id, contents) }) .await; - Ok(cx.add_model(|cx| { - let mut buffer = Buffer::build(text_buffer, diff_base, Some(Arc::new(file))); - buffer.git_diff_recalc(cx); - buffer - })) + Ok(cx.add_model(|_| Buffer::build(text_buffer, diff_base, Some(Arc::new(file))))) }) } From 8d662edb6c20c45b51a93fc22270425f7c95ce40 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 25 May 2023 14:29:28 -0400 Subject: [PATCH 3/5] Remove concept of git diff refresh from `Item` trait --- crates/diagnostics/src/diagnostics.rs | 9 --- crates/editor/src/element.rs | 14 ++-- crates/editor/src/items.rs | 11 --- crates/editor/src/multi_buffer.rs | 11 --- crates/language/src/buffer.rs | 1 - crates/project/src/project.rs | 93 ++++++++++++++++++---- crates/project/src/project_settings.rs | 16 ++++ crates/search/src/project_search.rs | 9 --- crates/workspace/src/item.rs | 66 ++------------- crates/workspace/src/workspace.rs | 4 +- crates/workspace/src/workspace_settings.rs | 2 - 11 files changed, 109 insertions(+), 127 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 182efdfdd6..b163a25d95 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -609,15 +609,6 @@ impl Item for ProjectDiagnosticsEditor { unreachable!() } - fn git_diff_recalc( - &mut self, - project: ModelHandle, - cx: &mut ViewContext, - ) -> Task> { - self.editor - .update(cx, |editor, cx| editor.git_diff_recalc(project, cx)) - } - fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> { Editor::to_item_events(event) } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 4e5863407f..6be0650848 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -40,7 +40,10 @@ use language::{ language_settings::ShowWhitespaceSetting, Bias, CursorShape, DiagnosticSeverity, OffsetUtf16, Selection, }; -use project::ProjectPath; +use project::{ + project_settings::{GitGutterSetting, ProjectSettings}, + ProjectPath, +}; use smallvec::SmallVec; use std::{ borrow::Cow, @@ -51,7 +54,7 @@ use std::{ sync::Arc, }; use text::Point; -use workspace::{item::Item, GitGutterSetting, WorkspaceSettings}; +use workspace::item::Item; enum FoldMarkers {} @@ -551,11 +554,8 @@ impl EditorElement { let scroll_top = scroll_position.y() * line_height; let show_gutter = matches!( - settings::get::(cx) - .git - .git_gutter - .unwrap_or_default(), - GitGutterSetting::TrackedFiles + settings::get::(cx).git.git_gutter, + Some(GitGutterSetting::TrackedFiles) ); if show_gutter { diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 483fd56cc5..40e7c89cb2 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -720,17 +720,6 @@ impl Item for Editor { }) } - fn git_diff_recalc( - &mut self, - _project: ModelHandle, - cx: &mut ViewContext, - ) -> Task> { - self.buffer().update(cx, |multibuffer, cx| { - multibuffer.git_diff_recalc(cx); - }); - Task::ready(Ok(())) - } - fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> { let mut result = SmallVec::new(); match event { diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index e749f5dcfb..d470dcbaaf 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -343,17 +343,6 @@ impl MultiBuffer { self.read(cx).symbols_containing(offset, theme) } - pub fn git_diff_recalc(&mut self, _: &mut ModelContext) { - // let buffers = self.buffers.borrow(); - // for buffer_state in buffers.values() { - // if buffer_state.buffer.read(cx).needs_git_diff_recalc() { - // buffer_state - // .buffer - // .update(cx, |buffer, cx| buffer.git_diff_recalc(cx)) - // } - // } - } - pub fn edit( &mut self, edits: I, diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index f6eb2a5d2d..27e9bfab38 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -620,7 +620,6 @@ impl Buffer { cx, ); } - self.git_diff_recalc(cx); cx.emit(Event::Reloaded); cx.notify(); } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 3f520c7e99..b66f525061 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1,6 +1,6 @@ mod ignore; mod lsp_command; -mod project_settings; +pub mod project_settings; pub mod search; pub mod terminals; pub mod worktree; @@ -14,7 +14,10 @@ use clock::ReplicaId; use collections::{hash_map, BTreeMap, HashMap, HashSet}; use copilot::Copilot; use futures::{ - channel::mpsc::{self, UnboundedReceiver}, + channel::{ + mpsc::{self, UnboundedReceiver}, + oneshot, + }, future::{try_join_all, Shared}, stream::FuturesUnordered, AsyncWriteExt, Future, FutureExt, StreamExt, TryFutureExt, @@ -131,6 +134,7 @@ pub struct Project { buffer_snapshots: HashMap>>, // buffer_id -> server_id -> vec of snapshots buffers_being_formatted: HashSet, buffers_needing_diff: HashSet>, + git_diff_debouncer: DelayedDebounced, nonce: u128, _maintain_buffer_languages: Task<()>, _maintain_workspace_config: Task<()>, @@ -138,6 +142,49 @@ pub struct Project { copilot_enabled: bool, } +struct DelayedDebounced { + task: Option>, + cancel_channel: Option>, +} + +impl DelayedDebounced { + fn new() -> DelayedDebounced { + DelayedDebounced { + task: None, + cancel_channel: None, + } + } + + fn fire_new(&mut self, delay: Duration, cx: &mut ModelContext, func: F) + where + F: 'static + FnOnce(&mut Project, &mut ModelContext) -> Task<()>, + { + if let Some(channel) = self.cancel_channel.take() { + _ = channel.send(()); + } + + let (sender, mut receiver) = oneshot::channel::<()>(); + self.cancel_channel = Some(sender); + + let previous_task = self.task.take(); + self.task = Some(cx.spawn(|workspace, mut cx| async move { + let mut timer = cx.background().timer(delay).fuse(); + if let Some(previous_task) = previous_task { + previous_task.await; + } + + futures::select_biased! { + _ = receiver => return, + _ = timer => {} + } + + workspace + .update(&mut cx, |workspace, cx| (func)(workspace, cx)) + .await; + })); + } +} + struct LspBufferSnapshot { version: i32, snapshot: TextBufferSnapshot, @@ -486,6 +533,7 @@ impl Project { last_workspace_edits_by_language_server: Default::default(), buffers_being_formatted: Default::default(), buffers_needing_diff: Default::default(), + git_diff_debouncer: DelayedDebounced::new(), nonce: StdRng::from_entropy().gen(), terminals: Terminals { local_handles: Vec::new(), @@ -576,6 +624,7 @@ impl Project { opened_buffers: Default::default(), buffers_being_formatted: Default::default(), buffers_needing_diff: Default::default(), + git_diff_debouncer: DelayedDebounced::new(), buffer_snapshots: Default::default(), nonce: StdRng::from_entropy().gen(), terminals: Terminals { @@ -2077,19 +2126,36 @@ impl Project { cx: &mut ModelContext, ) { self.buffers_needing_diff.insert(buffer.downgrade()); - if self.buffers_needing_diff.len() == 1 { - let this = cx.weak_handle(); - cx.defer(move |cx| { - if let Some(this) = this.upgrade(cx) { - this.update(cx, |this, cx| { - this.recalculate_buffer_diffs(cx); - }); - } + let first_insertion = self.buffers_needing_diff.len() == 1; + + let settings = settings::get::(cx); + let delay = if let Some(delay) = settings.git.gutter_debounce { + delay + } else { + if first_insertion { + let this = cx.weak_handle(); + cx.defer(move |cx| { + if let Some(this) = this.upgrade(cx) { + this.update(cx, |this, cx| { + this.recalculate_buffer_diffs(cx).detach(); + }); + } + }); + } + return; + }; + + const MIN_DELAY: u64 = 50; + let delay = delay.max(MIN_DELAY); + let duration = Duration::from_millis(delay); + + self.git_diff_debouncer + .fire_new(duration, cx, move |this, cx| { + this.recalculate_buffer_diffs(cx) }); - } } - fn recalculate_buffer_diffs(&mut self, cx: &mut ModelContext) { + fn recalculate_buffer_diffs(&mut self, cx: &mut ModelContext) -> Task<()> { cx.spawn(|this, mut cx| async move { let buffers: Vec<_> = this.update(&mut cx, |this, _| { this.buffers_needing_diff.drain().collect() @@ -2109,7 +2175,7 @@ impl Project { this.update(&mut cx, |this, cx| { if !this.buffers_needing_diff.is_empty() { - this.recalculate_buffer_diffs(cx); + this.recalculate_buffer_diffs(cx).detach(); } else { // TODO: Would a `ModelContext.notify()` suffice here? for buffer in buffers { @@ -2120,7 +2186,6 @@ impl Project { } }); }) - .detach(); } fn language_servers_for_worktree( diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index c542d1d13f..607b284813 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -8,6 +8,22 @@ use std::sync::Arc; pub struct ProjectSettings { #[serde(default)] pub lsp: HashMap, LspSettings>, + #[serde(default)] + pub git: GitSettings, +} + +#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] +pub struct GitSettings { + pub git_gutter: Option, + pub gutter_debounce: Option, +} + +#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum GitGutterSetting { + #[default] + TrackedFiles, + Hide, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 915957401d..d86823d224 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -360,15 +360,6 @@ impl Item for ProjectSearchView { .update(cx, |editor, cx| editor.navigate(data, cx)) } - fn git_diff_recalc( - &mut self, - project: ModelHandle, - cx: &mut ViewContext, - ) -> Task> { - self.results_editor - .update(cx, |editor, cx| editor.git_diff_recalc(project, cx)) - } - fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> { match event { ViewEvent::UpdateTab => { diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index c947078015..9a3fb5e475 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -1,9 +1,8 @@ use crate::{ - pane, persistence::model::ItemId, searchable::SearchableItemHandle, DelayedDebouncedEditAction, - FollowableItemBuilders, ItemNavHistory, Pane, ToolbarItemLocation, ViewId, Workspace, - WorkspaceId, + pane, persistence::model::ItemId, searchable::SearchableItemHandle, FollowableItemBuilders, + ItemNavHistory, Pane, ToolbarItemLocation, ViewId, Workspace, WorkspaceId, }; -use crate::{AutosaveSetting, WorkspaceSettings}; +use crate::{AutosaveSetting, DelayedDebouncedEditAction, WorkspaceSettings}; use anyhow::Result; use client::{proto, Client}; use gpui::{ @@ -102,13 +101,6 @@ pub trait Item: View { ) -> Task> { unimplemented!("reload() must be implemented if can_save() returns true") } - fn git_diff_recalc( - &mut self, - _project: ModelHandle, - _cx: &mut ViewContext, - ) -> Task> { - Task::ready(Ok(())) - } fn to_item_events(_event: &Self::Event) -> SmallVec<[ItemEvent; 2]> { SmallVec::new() } @@ -221,11 +213,6 @@ pub trait ItemHandle: 'static + fmt::Debug { cx: &mut WindowContext, ) -> Task>; fn reload(&self, project: ModelHandle, cx: &mut WindowContext) -> Task>; - fn git_diff_recalc( - &self, - project: ModelHandle, - cx: &mut WindowContext, - ) -> Task>; fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle>; fn to_followable_item_handle(&self, cx: &AppContext) -> Option>; fn on_release( @@ -381,7 +368,6 @@ impl ItemHandle for ViewHandle { .is_none() { let mut pending_autosave = DelayedDebouncedEditAction::new(); - let mut pending_git_update = DelayedDebouncedEditAction::new(); let pending_update = Rc::new(RefCell::new(None)); let pending_update_scheduled = Rc::new(AtomicBool::new(false)); @@ -450,48 +436,14 @@ impl ItemHandle for ViewHandle { } ItemEvent::Edit => { - let settings = settings::get::(cx); - let debounce_delay = settings.git.gutter_debounce; - - if let AutosaveSetting::AfterDelay { milliseconds } = - settings.autosave - { + let autosave = settings::get::(cx).autosave; + if let AutosaveSetting::AfterDelay { milliseconds } = autosave { let delay = Duration::from_millis(milliseconds); let item = item.clone(); pending_autosave.fire_new(delay, cx, move |workspace, cx| { Pane::autosave_item(&item, workspace.project().clone(), cx) }); } - - let item = item.clone(); - - if let Some(delay) = debounce_delay { - const MIN_GIT_DELAY: u64 = 50; - - let delay = delay.max(MIN_GIT_DELAY); - let duration = Duration::from_millis(delay); - - pending_git_update.fire_new( - duration, - cx, - move |workspace, cx| { - item.git_diff_recalc(workspace.project().clone(), cx) - }, - ); - } else { - cx.spawn(|workspace, mut cx| async move { - workspace - .update(&mut cx, |workspace, cx| { - item.git_diff_recalc( - workspace.project().clone(), - cx, - ) - })? - .await?; - anyhow::Ok(()) - }) - .detach_and_log_err(cx); - } } _ => {} @@ -576,14 +528,6 @@ impl ItemHandle for ViewHandle { self.update(cx, |item, cx| item.reload(project, cx)) } - fn git_diff_recalc( - &self, - project: ModelHandle, - cx: &mut WindowContext, - ) -> Task> { - self.update(cx, |item, cx| item.git_diff_recalc(project, cx)) - } - fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle> { self.read(cx).act_as_type(type_id, self, cx) } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 0510d89cef..346fa7637d 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -442,7 +442,7 @@ impl DelayedDebouncedEditAction { } } - fn fire_new(&mut self, delay: Duration, cx: &mut ViewContext, f: F) + fn fire_new(&mut self, delay: Duration, cx: &mut ViewContext, func: F) where F: 'static + FnOnce(&mut Workspace, &mut ViewContext) -> Task>, { @@ -466,7 +466,7 @@ impl DelayedDebouncedEditAction { } if let Some(result) = workspace - .update(&mut cx, |workspace, cx| (f)(workspace, cx)) + .update(&mut cx, |workspace, cx| (func)(workspace, cx)) .log_err() { result.await.log_err(); diff --git a/crates/workspace/src/workspace_settings.rs b/crates/workspace/src/workspace_settings.rs index 4202c00a8d..6483167018 100644 --- a/crates/workspace/src/workspace_settings.rs +++ b/crates/workspace/src/workspace_settings.rs @@ -8,7 +8,6 @@ pub struct WorkspaceSettings { pub confirm_quit: bool, pub show_call_status_icon: bool, pub autosave: AutosaveSetting, - pub git: GitSettings, } #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] @@ -17,7 +16,6 @@ pub struct WorkspaceSettingsContent { pub confirm_quit: Option, pub show_call_status_icon: Option, pub autosave: Option, - pub git: Option, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] From f40c49849105b4b00ab7fc16500fbabd119ec0a2 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 25 May 2023 10:31:19 -0400 Subject: [PATCH 4/5] Fix tests --- crates/diagnostics/src/diagnostics.rs | 1 + crates/file_finder/src/file_finder.rs | 1 + crates/project/src/project_tests.rs | 1 + crates/project_panel/src/project_panel.rs | 1 + crates/search/src/project_search.rs | 1 + crates/zed/src/zed.rs | 1 + 6 files changed, 6 insertions(+) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index b163a25d95..12fcc1395b 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -1499,6 +1499,7 @@ mod tests { language::init(cx); client::init_settings(cx); workspace::init_settings(cx); + Project::init_settings(cx); }); } diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 6d2ba115b7..c4fce49152 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -1198,6 +1198,7 @@ mod tests { super::init(cx); editor::init(cx); workspace::init_settings(cx); + Project::init_settings(cx); state }) } diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index e48ce6258b..285e3ee9b6 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -1273,6 +1273,7 @@ async fn test_transforming_diagnostics(cx: &mut gpui::TestAppContext) { // The diagnostics have moved down since they were created. buffer.next_notification(cx).await; + buffer.next_notification(cx).await; buffer.read_with(cx, |buffer, _| { assert_eq!( buffer diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 6604472d86..8584d3f6b9 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -2229,6 +2229,7 @@ mod tests { editor::init_settings(cx); crate::init(cx); workspace::init_settings(cx); + Project::init_settings(cx); }); } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index d86823d224..7d95ec232d 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -1268,6 +1268,7 @@ pub mod tests { client::init_settings(cx); editor::init_settings(cx); workspace::init_settings(cx); + Project::init_settings(cx); }); } } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 1dfe9c24e5..619dd81a80 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -2085,6 +2085,7 @@ mod tests { theme::init((), cx); call::init(app_state.client.clone(), app_state.user_store.clone(), cx); workspace::init(app_state.clone(), cx); + Project::init_settings(cx); language::init(cx); editor::init(cx); project_panel::init_settings(cx); From 5e39ba596e1b29dc08c08c02c2355e6e91b17514 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 25 May 2023 14:09:34 -0400 Subject: [PATCH 5/5] Clean up final remaining code paths calling old diff update method --- crates/editor/src/editor.rs | 2 + crates/editor/src/editor_tests.rs | 42 +++--- crates/editor/src/multi_buffer.rs | 120 +++++++++++------- crates/editor/src/test/editor_test_context.rs | 10 +- crates/git/src/diff.rs | 7 - crates/language/src/buffer.rs | 70 ++-------- crates/project/src/project.rs | 7 +- crates/project_panel/src/project_panel.rs | 1 + 8 files changed, 117 insertions(+), 142 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 5a504a610c..f5d109e15b 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6873,6 +6873,7 @@ impl Editor { multi_buffer::Event::Saved => cx.emit(Event::Saved), multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged), multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged), + multi_buffer::Event::DiffBaseChanged => cx.emit(Event::DiffBaseChanged), multi_buffer::Event::Closed => cx.emit(Event::Closed), multi_buffer::Event::DiagnosticsUpdated => { self.refresh_active_diagnostics(cx); @@ -7261,6 +7262,7 @@ pub enum Event { DirtyChanged, Saved, TitleChanged, + DiffBaseChanged, SelectionsChanged { local: bool, }, diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 180de155e9..bc671b9ffc 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -1246,7 +1246,7 @@ fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut TestAppContext) { #[gpui::test] async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); cx.simulate_window_resize(cx.window_id, vec2f(100., 4. * line_height)); @@ -1358,7 +1358,7 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon #[gpui::test] async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); cx.simulate_window_resize(cx.window_id, vec2f(100., 4. * line_height)); @@ -1473,7 +1473,7 @@ async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { #[gpui::test] async fn test_delete_to_beginning_of_line(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; cx.set_state("one «two threeˇ» four"); cx.update_editor(|editor, cx| { editor.delete_to_beginning_of_line(&DeleteToBeginningOfLine, cx); @@ -1637,7 +1637,7 @@ async fn test_newline_above(cx: &mut gpui::TestAppContext) { .unwrap(), ); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx)); cx.set_state(indoc! {" const a: ˇA = ( @@ -1685,7 +1685,7 @@ async fn test_newline_below(cx: &mut gpui::TestAppContext) { .unwrap(), ); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx)); cx.set_state(indoc! {" const a: ˇA = ( @@ -1751,7 +1751,7 @@ async fn test_tab(cx: &mut gpui::TestAppContext) { settings.defaults.tab_size = NonZeroU32::new(3) }); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; cx.set_state(indoc! {" ˇabˇc ˇ🏀ˇ🏀ˇefg @@ -1779,7 +1779,7 @@ async fn test_tab(cx: &mut gpui::TestAppContext) { async fn test_tab_in_leading_whitespace_auto_indents_lines(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; let language = Arc::new( Language::new( LanguageConfig::default(), @@ -1850,7 +1850,7 @@ async fn test_tab_with_mixed_whitespace(cx: &mut gpui::TestAppContext) { .unwrap(), ); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx)); cx.set_state(indoc! {" fn a() { @@ -1876,7 +1876,7 @@ async fn test_indent_outdent(cx: &mut gpui::TestAppContext) { settings.defaults.tab_size = NonZeroU32::new(4); }); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; cx.set_state(indoc! {" «oneˇ» «twoˇ» @@ -1949,7 +1949,7 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut gpui::TestAppContext) { settings.defaults.hard_tabs = Some(true); }); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; // select two ranges on one line cx.set_state(indoc! {" @@ -2156,7 +2156,7 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) { async fn test_backspace(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; // Basic backspace cx.set_state(indoc! {" @@ -2205,7 +2205,7 @@ async fn test_backspace(cx: &mut gpui::TestAppContext) { async fn test_delete(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; cx.set_state(indoc! {" onˇe two three fou«rˇ» five six @@ -2559,7 +2559,7 @@ fn test_transpose(cx: &mut TestAppContext) { async fn test_clipboard(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; cx.set_state("«one✅ ˇ»two «three ˇ»four «five ˇ»six "); cx.update_editor(|e, cx| e.cut(&Cut, cx)); @@ -2641,7 +2641,7 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) { async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; let language = Arc::new(Language::new( LanguageConfig::default(), Some(tree_sitter_rust::language()), @@ -3085,7 +3085,7 @@ fn test_add_selection_above_below(cx: &mut TestAppContext) { async fn test_select_next(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; cx.set_state("abc\nˇabc abc\ndefabc\nabc"); cx.update_editor(|e, cx| e.select_next(&SelectNext::default(), cx)); @@ -3314,7 +3314,7 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) { async fn test_autoclose_pairs(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; let language = Arc::new(Language::new( LanguageConfig { @@ -3485,7 +3485,7 @@ async fn test_autoclose_pairs(cx: &mut gpui::TestAppContext) { async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; let html_language = Arc::new( Language::new( @@ -3721,7 +3721,7 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) { async fn test_autoclose_with_overrides(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; let rust_language = Arc::new( Language::new( @@ -4938,7 +4938,7 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) let registry = Arc::new(LanguageRegistry::test()); registry.add(language.clone()); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; cx.update_buffer(|buffer, cx| { buffer.set_language_registry(registry); buffer.set_language(Some(language), cx); @@ -5060,7 +5060,7 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; let html_language = Arc::new( Language::new( @@ -5985,7 +5985,7 @@ fn test_combine_syntax_and_fuzzy_match_highlights() { async fn go_to_hunk(deterministic: Arc, cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); - let mut cx = EditorTestContext::new(cx); + let mut cx = EditorTestContext::new(cx).await; let diff_base = r#" use some::mod; diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index d470dcbaaf..4650dff38f 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -66,6 +66,7 @@ pub enum Event { }, Edited, Reloaded, + DiffBaseChanged, LanguageChanged, Reparsed, Saved, @@ -1301,6 +1302,7 @@ impl MultiBuffer { language::Event::Saved => Event::Saved, language::Event::FileHandleChanged => Event::FileHandleChanged, language::Event::Reloaded => Event::Reloaded, + language::Event::DiffBaseChanged => Event::DiffBaseChanged, language::Event::LanguageChanged => Event::LanguageChanged, language::Event::Reparsed => Event::Reparsed, language::Event::DiagnosticsUpdated => Event::DiagnosticsUpdated, @@ -1539,6 +1541,13 @@ impl MultiBuffer { cx.add_model(|cx| Self::singleton(buffer, cx)) } + pub fn build_from_buffer( + buffer: ModelHandle, + cx: &mut gpui::AppContext, + ) -> ModelHandle { + cx.add_model(|cx| Self::singleton(buffer, cx)) + } + pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::AppContext) -> ModelHandle { cx.add_model(|cx| { let mut multibuffer = MultiBuffer::new(0); @@ -3859,10 +3868,13 @@ where #[cfg(test)] mod tests { + use crate::editor_tests::init_test; + use super::*; use futures::StreamExt; use gpui::{AppContext, TestAppContext}; use language::{Buffer, Rope}; + use project::{FakeFs, Project}; use rand::prelude::*; use settings::SettingsStore; use std::{env, rc::Rc}; @@ -4553,73 +4565,85 @@ mod tests { #[gpui::test] async fn test_diff_hunks_in_range(cx: &mut TestAppContext) { use git::diff::DiffHunkStatus; + init_test(cx, |_| {}); + + let fs = FakeFs::new(cx.background()); + let project = Project::test(fs, [], cx).await; // buffer has two modified hunks with two rows each - let buffer_1 = cx.add_model(|cx| { - let mut buffer = Buffer::new( - 0, - " - 1.zero - 1.ONE - 1.TWO - 1.three - 1.FOUR - 1.FIVE - 1.six - " - .unindent(), - cx, - ); + let buffer_1 = project + .update(cx, |project, cx| { + project.create_buffer( + " + 1.zero + 1.ONE + 1.TWO + 1.three + 1.FOUR + 1.FIVE + 1.six + " + .unindent() + .as_str(), + None, + cx, + ) + }) + .unwrap(); + buffer_1.update(cx, |buffer, cx| { buffer.set_diff_base( Some( " - 1.zero - 1.one - 1.two - 1.three - 1.four - 1.five - 1.six - " + 1.zero + 1.one + 1.two + 1.three + 1.four + 1.five + 1.six + " .unindent(), ), cx, ); - buffer }); // buffer has a deletion hunk and an insertion hunk - let buffer_2 = cx.add_model(|cx| { - let mut buffer = Buffer::new( - 0, - " - 2.zero - 2.one - 2.two - 2.three - 2.four - 2.five - 2.six - " - .unindent(), - cx, - ); + let buffer_2 = project + .update(cx, |project, cx| { + project.create_buffer( + " + 2.zero + 2.one + 2.two + 2.three + 2.four + 2.five + 2.six + " + .unindent() + .as_str(), + None, + cx, + ) + }) + .unwrap(); + buffer_2.update(cx, |buffer, cx| { buffer.set_diff_base( Some( " - 2.zero - 2.one - 2.one-and-a-half - 2.two - 2.three - 2.four - 2.six - " + 2.zero + 2.one + 2.one-and-a-half + 2.two + 2.three + 2.four + 2.six + " .unindent(), ), cx, ); - buffer }); cx.foreground().run_until_parked(); diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs index e520562ebb..95da7ff297 100644 --- a/crates/editor/src/test/editor_test_context.rs +++ b/crates/editor/src/test/editor_test_context.rs @@ -7,6 +7,7 @@ use gpui::{ }; use indoc::indoc; use language::{Buffer, BufferSnapshot}; +use project::{FakeFs, Project}; use std::{ any::TypeId, ops::{Deref, DerefMut, Range}, @@ -25,11 +26,16 @@ pub struct EditorTestContext<'a> { } impl<'a> EditorTestContext<'a> { - pub fn new(cx: &'a mut gpui::TestAppContext) -> EditorTestContext<'a> { + pub async fn new(cx: &'a mut gpui::TestAppContext) -> EditorTestContext<'a> { + let fs = FakeFs::new(cx.background()); + let project = Project::test(fs, [], cx).await; + let buffer = project + .update(cx, |project, cx| project.create_buffer("", None, cx)) + .unwrap(); let (window_id, editor) = cx.update(|cx| { cx.add_window(Default::default(), |cx| { cx.focus_self(); - build_editor(MultiBuffer::build_simple("", cx), cx) + build_editor(MultiBuffer::build_from_buffer(buffer, cx), cx) }) }); diff --git a/crates/git/src/diff.rs b/crates/git/src/diff.rs index 8260dfc98d..39383cfc78 100644 --- a/crates/git/src/diff.rs +++ b/crates/git/src/diff.rs @@ -161,13 +161,6 @@ impl BufferDiff { self.tree = SumTree::new(); } - pub fn needs_update(&self, buffer: &text::BufferSnapshot) -> bool { - match &self.last_buffer_version { - Some(last) => buffer.version().changed_since(last), - None => true, - } - } - pub async fn update(&mut self, diff_base: &str, buffer: &text::BufferSnapshot) { let mut tree = SumTree::new(); diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 27e9bfab38..93b50cf597 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -50,16 +50,10 @@ pub use {tree_sitter_rust, tree_sitter_typescript}; pub use lsp::DiagnosticSeverity; -struct GitDiffStatus { - diff: git::diff::BufferDiff, - update_in_progress: bool, - update_requested: bool, -} - pub struct Buffer { text: TextBuffer, diff_base: Option, - git_diff_status: GitDiffStatus, + git_diff: git::diff::BufferDiff, file: Option>, saved_version: clock::Global, saved_version_fingerprint: RopeFingerprint, @@ -195,6 +189,7 @@ pub enum Event { Saved, FileHandleChanged, Reloaded, + DiffBaseChanged, LanguageChanged, Reparsed, DiagnosticsUpdated, @@ -466,11 +461,7 @@ impl Buffer { was_dirty_before_starting_transaction: None, text: buffer, diff_base, - git_diff_status: GitDiffStatus { - diff: git::diff::BufferDiff::new(), - update_in_progress: false, - update_requested: false, - }, + git_diff: git::diff::BufferDiff::new(), file, syntax_map: Mutex::new(SyntaxMap::new()), parsing_in_background: false, @@ -501,7 +492,7 @@ impl Buffer { BufferSnapshot { text, syntax, - git_diff: self.git_diff_status.diff.clone(), + git_diff: self.git_diff.clone(), file: self.file.clone(), remote_selections: self.remote_selections.clone(), diagnostics: self.diagnostics.clone(), @@ -675,17 +666,14 @@ impl Buffer { pub fn set_diff_base(&mut self, diff_base: Option, cx: &mut ModelContext) { self.diff_base = diff_base; self.git_diff_recalc(cx); + cx.emit(Event::DiffBaseChanged); } - pub fn needs_git_diff_recalc(&self) -> bool { - self.git_diff_status.diff.needs_update(self) - } - - pub fn git_diff_recalc_2(&mut self, cx: &mut ModelContext) -> Option> { + pub fn git_diff_recalc(&mut self, cx: &mut ModelContext) -> Option> { let diff_base = self.diff_base.clone()?; // TODO: Make this an Arc let snapshot = self.snapshot(); - let mut diff = self.git_diff_status.diff.clone(); + let mut diff = self.git_diff.clone(); let diff = cx.background().spawn(async move { diff.update(&diff_base, &snapshot).await; diff @@ -696,55 +684,13 @@ impl Buffer { let buffer_diff = diff.await; if let Some(this) = handle.upgrade(&mut cx) { this.update(&mut cx, |this, _| { - this.git_diff_status.diff = buffer_diff; + this.git_diff = buffer_diff; this.git_diff_update_count += 1; }) } })) } - fn git_diff_recalc(&mut self, cx: &mut ModelContext) { - if self.git_diff_status.update_in_progress { - self.git_diff_status.update_requested = true; - return; - } - - if let Some(diff_base) = &self.diff_base { - self.git_diff_status.update_in_progress = true; - let snapshot = self.snapshot(); - let diff_base = diff_base.clone(); - - let mut diff = self.git_diff_status.diff.clone(); - let diff = cx.background().spawn(async move { - diff.update(&diff_base, &snapshot).await; - diff - }); - - cx.spawn_weak(|this, mut cx| async move { - let buffer_diff = diff.await; - if let Some(this) = this.upgrade(&cx) { - this.update(&mut cx, |this, cx| { - this.git_diff_status.diff = buffer_diff; - this.git_diff_update_count += 1; - cx.notify(); - - if this.git_diff_status.update_requested { - this.git_diff_recalc(cx); - } else { - this.git_diff_status.update_in_progress = false; - } - }) - } - }) - .detach() - } else { - let snapshot = self.snapshot(); - self.git_diff_status.diff.clear(&snapshot); - self.git_diff_update_count += 1; - cx.notify(); - } - } - pub fn close(&mut self, cx: &mut ModelContext) { cx.emit(Event::Closed); } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index b66f525061..6a6f878978 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1977,7 +1977,10 @@ impl Project { event: &BufferEvent, cx: &mut ModelContext, ) -> Option<()> { - if matches!(event, BufferEvent::Edited { .. } | BufferEvent::Reloaded) { + if matches!( + event, + BufferEvent::Edited { .. } | BufferEvent::Reloaded | BufferEvent::DiffBaseChanged + ) { self.request_buffer_diff_recalculation(&buffer, cx); } @@ -2166,7 +2169,7 @@ impl Project { .iter() .filter_map(|buffer| { let buffer = buffer.upgrade(cx)?; - buffer.update(cx, |buffer, cx| buffer.git_diff_recalc_2(cx)) + buffer.update(cx, |buffer, cx| buffer.git_diff_recalc(cx)) }) .collect() }); diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 8584d3f6b9..33e4340f22 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -2244,6 +2244,7 @@ mod tests { pane::init(cx); crate::init(cx); workspace::init(app_state.clone(), cx); + Project::init_settings(cx); }); }