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 5539d1d941726148fc543a59652d57190e1d400d..93955a247482d09eb1155f530f644fcaee62162b 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 391a698a1b7dd17fba4161665cb65edd5df4943e..f93d7d4b5051480b92a3bedf30b2633d36ac6741 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 6b1ad6c5b2d6eb7c2e7bd9be9376b5fad04b8dd7..e749f5dcfb077a0d93d81d6329aa975b24752686 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 93955a247482d09eb1155f530f644fcaee62162b..f6eb2a5d2d2813890af69c06b6a45cc2e2d2e9c3 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 f93d7d4b5051480b92a3bedf30b2633d36ac6741..3f520c7e9924f73239881852abb199904bed22b8 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 d2c035f91675a779b84a4facfc6331091b481910..3a7044de0c705be6084401c2f90e9ef2b007e1d7 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 182efdfdd6c520e30d285ed822f66f9a3f98a368..b163a25d95b6dd5bd35f1b03248781810bed2afa 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 4e5863407f208ae0d4b0b84030d1b21521164ec6..6be065084814e570a0411ffb91df4a4eb380e1ac 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 483fd56cc5f3c3934aeb4619525ee7746567cdae..40e7c89cb298e34510002550349f7faff6f0fa19 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 e749f5dcfb077a0d93d81d6329aa975b24752686..d470dcbaaf8d84c3b2637285269d9848cbdb732f 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 f6eb2a5d2d2813890af69c06b6a45cc2e2d2e9c3..27e9bfab389fe867129c9ea9401faede613622d2 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 3f520c7e9924f73239881852abb199904bed22b8..b66f525061c8292d40d3f30540b91e91cb021d85 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 c542d1d13fd42c3cd2721c92981e74129556a554..607b2848139aa88b1d36821030507de8c85ed72a 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 915957401d440c40dd13d4b3364b0be76e09f3ef..d86823d2249e304103dd4a3b449c69769e34ea81 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 c9470780153608e25bf879f94109e61626673cc4..9a3fb5e475dd0c612fecccfefdecab95606bb776 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 0510d89cefc2096b1ee622cd825396b01a25d6ee..346fa7637d7659c62d40a39b6c7b3c5b6c339bfa 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 4202c00a8d7a9fb6384280977493896ab5906fbc..64831670189696ecd8c90877193af0fb11c8239b 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 b163a25d95b6dd5bd35f1b03248781810bed2afa..12fcc1395bf5a430452f1647cc197aa07df91f4b 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 6d2ba115b7f7eadaf4c2aa51903f0fdb95adae38..c4fce491523134e2b7f64678cd89da121fff251f 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 e48ce6258b34f38f438dd6035a533a99a0be5d0a..285e3ee9b678c71708f13c66e6af11b41a80ac48 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 6604472d863ac338b98fe7f088c37b68db122d54..8584d3f6b98000d075102efa9b2b5875a52df0d7 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 d86823d2249e304103dd4a3b449c69769e34ea81..7d95ec232d8359dac2755a1b96fa754914b5ede1 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 1dfe9c24e54dd15f098d2a4e5d1df2f2c2e75f1e..619dd81a80407faf2f001fb4d47449bee98938bf 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 5a504a610cd63529e80e0b1a6f872f0fe08fb8bd..f5d109e15bd2138fba6914e058b575a5bdf42e80 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 180de155e998fff1492c22311502d87ebcf744bf..bc671b9ffc3652856d16faf567784eab438440b7 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 d470dcbaaf8d84c3b2637285269d9848cbdb732f..4650dff38f58088eab5fc1638080680dc86dd84e 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 e520562ebba1d410e58e9ae3a9438899701a62c5..95da7ff297341e18f99ca57f7cbcadb707a8fdb4 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 8260dfc98d9834f8cefff6dfc274a4d7a9e237d7..39383cfc78b297e355c1d4c096219069cd92b1da 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 27e9bfab389fe867129c9ea9401faede613622d2..93b50cf597cfd3e0ed18ac8e317fa5847740f1b1 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 b66f525061c8292d40d3f30540b91e91cb021d85..6a6f87897860ebe09b81326553c1bf779012cc88 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 8584d3f6b98000d075102efa9b2b5875a52df0d7..33e4340f2254f8fb6c97ba0e283ff4347446ea00 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); }); }