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); }); }