diff --git a/crates/breadcrumbs/src/breadcrumbs.rs b/crates/breadcrumbs/src/breadcrumbs.rs index ce36e440ad..ff4443a570 100644 --- a/crates/breadcrumbs/src/breadcrumbs.rs +++ b/crates/breadcrumbs/src/breadcrumbs.rs @@ -148,7 +148,7 @@ impl ToolbarItemView for Breadcrumbs { } } - fn pane_focus_update(&mut self, pane_focused: bool, _: &mut gpui::AppContext) { + fn pane_focus_update(&mut self, pane_focused: bool, _: &mut ViewContext) { self.pane_focused = pane_focused; } } diff --git a/crates/copilot/src/sign_in.rs b/crates/copilot/src/sign_in.rs index d36eba922d..c08fc1be53 100644 --- a/crates/copilot/src/sign_in.rs +++ b/crates/copilot/src/sign_in.rs @@ -26,27 +26,31 @@ pub fn init(cx: &mut AppContext) { match &status { crate::Status::SigningIn { prompt } => { - if let Some(code_verification_handle) = code_verification.as_mut() { - if cx.has_window(code_verification_handle.window_id()) { - code_verification_handle.update(cx, |code_verification_view, cx| { - code_verification_view.set_status(status, cx); - cx.activate_window(); + if let Some(code_verification) = code_verification.as_mut() { + if cx.has_window(code_verification.window_id()) { + cx.update_window(code_verification.window_id(), |cx| { + code_verification.update(cx, |code_verification_view, cx| { + code_verification_view.set_status(status, cx); + cx.activate_window(); + }); }); } else { - create_copilot_auth_window(cx, &status, &mut code_verification); + *code_verification = create_copilot_auth_window(cx, &status); } } else if let Some(_prompt) = prompt { - create_copilot_auth_window(cx, &status, &mut code_verification); + code_verification = Some(create_copilot_auth_window(cx, &status)); } } Status::Authorized | Status::Unauthorized => { if let Some(code_verification) = code_verification.as_ref() { - code_verification.update(cx, |code_verification, cx| { - code_verification.set_status(status, cx); - cx.activate_window(); - }); + cx.update_window(code_verification.window_id(), |cx| { + code_verification.update(cx, |code_verification, cx| { + code_verification.set_status(status, cx); + cx.activate_window(); + }); - cx.platform().activate(true); + cx.platform().activate(true); + }); } } _ => { @@ -62,8 +66,7 @@ pub fn init(cx: &mut AppContext) { fn create_copilot_auth_window( cx: &mut AppContext, status: &Status, - code_verification: &mut Option>, -) { +) -> ViewHandle { let window_size = cx.global::().theme.copilot.modal.dimensions(); let window_options = WindowOptions { bounds: WindowBounds::Fixed(RectF::new(Default::default(), window_size)), @@ -77,7 +80,7 @@ fn create_copilot_auth_window( let (_, view) = cx.add_window(window_options, |_cx| { CopilotCodeVerification::new(status.clone()) }); - *code_verification = Some(view); + view } pub struct CopilotCodeVerification { diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 516630b185..90154415d5 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -765,7 +765,7 @@ mod tests { display_map::{BlockContext, TransformBlock}, DisplayPoint, }; - use gpui::TestAppContext; + use gpui::{TestAppContext, WindowContext}; use language::{Diagnostic, DiagnosticEntry, DiagnosticSeverity, PointUtf16, Unclipped}; use serde_json::json; use unindent::Unindent as _; @@ -1175,7 +1175,7 @@ mod tests { }); } - fn editor_blocks(editor: &ViewHandle, cx: &mut AppContext) -> Vec<(u32, String)> { + fn editor_blocks(editor: &ViewHandle, cx: &mut WindowContext) -> Vec<(u32, String)> { editor.update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); snapshot diff --git a/crates/drag_and_drop/src/drag_and_drop.rs b/crates/drag_and_drop/src/drag_and_drop.rs index 81b14a175c..dafb24a379 100644 --- a/crates/drag_and_drop/src/drag_and_drop.rs +++ b/crates/drag_and_drop/src/drag_and_drop.rs @@ -6,7 +6,7 @@ use gpui::{ geometry::{rect::RectF, vector::Vector2F}, platform::{CursorStyle, MouseButton}, scene::{MouseDown, MouseDrag}, - AppContext, Drawable, Element, View, ViewContext, WeakViewHandle, + Drawable, Element, View, ViewContext, WeakViewHandle, WindowContext, }; const DEAD_ZONE: f32 = 4.; @@ -263,7 +263,7 @@ impl DragAndDrop { }) } - pub fn cancel_dragging(&mut self, cx: &mut AppContext) { + pub fn cancel_dragging(&mut self, cx: &mut WindowContext) { if let Some(State::Dragging { payload, window_id, .. }) = &self.currently_dragged @@ -276,13 +276,13 @@ impl DragAndDrop { } } - fn finish_dragging(&mut self, cx: &mut AppContext) { + fn finish_dragging(&mut self, cx: &mut WindowContext) { if let Some(State::Dragging { window_id, .. }) = self.currently_dragged.take() { self.notify_containers_for_window(window_id, cx); } } - fn notify_containers_for_window(&mut self, window_id: usize, cx: &mut AppContext) { + fn notify_containers_for_window(&mut self, window_id: usize, cx: &mut WindowContext) { self.containers.retain(|container| { if let Some(container) = container.upgrade(cx) { if container.window_id() == window_id { diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 7c7909fed0..b86f6af8b5 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -9,7 +9,7 @@ use gpui::{ executor::Deterministic, geometry::{rect::RectF, vector::vec2f}, platform::{WindowBounds, WindowOptions}, - serde_json, + serde_json, TestAppContext, }; use indoc::indoc; use language::{BracketPairConfig, FakeLspAdapter, LanguageConfig, LanguageRegistry, Point}; @@ -28,8 +28,8 @@ use workspace::{ }; #[gpui::test] -fn test_edit_events(cx: &mut AppContext) { - cx.set_global(Settings::test(cx)); +fn test_edit_events(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); let buffer = cx.add_model(|cx| { let mut buffer = language::Buffer::new(0, "123456", cx); buffer.set_group_interval(Duration::from_secs(1)); @@ -37,7 +37,7 @@ fn test_edit_events(cx: &mut AppContext) { }); let events = Rc::new(RefCell::new(Vec::new())); - let (_, editor1) = cx.add_window(Default::default(), { + let (_, editor1) = cx.add_window({ let events = events.clone(); |cx| { cx.subscribe(&cx.handle(), move |_, _, event, _| { @@ -52,7 +52,7 @@ fn test_edit_events(cx: &mut AppContext) { Editor::for_buffer(buffer.clone(), None, cx) } }); - let (_, editor2) = cx.add_window(Default::default(), { + let (_, editor2) = cx.add_window({ let events = events.clone(); |cx| { cx.subscribe(&cx.handle(), move |_, _, event, _| { @@ -155,13 +155,13 @@ fn test_edit_events(cx: &mut AppContext) { } #[gpui::test] -fn test_undo_redo_with_selection_restoration(cx: &mut AppContext) { - cx.set_global(Settings::test(cx)); +fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); let mut now = Instant::now(); let buffer = cx.add_model(|cx| language::Buffer::new(0, "123456", cx)); - let group_interval = buffer.read(cx).transaction_group_interval(); + let group_interval = buffer.read_with(cx, |buffer, _| buffer.transaction_group_interval()); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx)); + let (_, editor) = cx.add_window(|cx| build_editor(buffer.clone(), cx)); editor.update(cx, |editor, cx| { editor.start_transaction_at(now, cx); @@ -225,8 +225,8 @@ fn test_undo_redo_with_selection_restoration(cx: &mut AppContext) { } #[gpui::test] -fn test_ime_composition(cx: &mut AppContext) { - cx.set_global(Settings::test(cx)); +fn test_ime_composition(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); let buffer = cx.add_model(|cx| { let mut buffer = language::Buffer::new(0, "abcde", cx); // Ensure automatic grouping doesn't occur. @@ -235,7 +235,7 @@ fn test_ime_composition(cx: &mut AppContext) { }); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - cx.add_window(Default::default(), |cx| { + cx.add_window(|cx| { let mut editor = build_editor(buffer.clone(), cx); // Start a new IME composition. @@ -327,11 +327,13 @@ fn test_ime_composition(cx: &mut AppContext) { } #[gpui::test] -fn test_selection_with_mouse(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); +fn test_selection_with_mouse(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); - let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\nddddddd\n", cx); - let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); + let (_, editor) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\nddddddd\n", cx); + build_editor(buffer, cx) + }); editor.update(cx, |view, cx| { view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx); }); @@ -392,10 +394,12 @@ fn test_selection_with_mouse(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_canceling_pending_selection(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_canceling_pending_selection(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx); @@ -424,7 +428,7 @@ fn test_canceling_pending_selection(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_clone(cx: &mut gpui::AppContext) { +fn test_clone(cx: &mut TestAppContext) { let (text, selection_ranges) = marked_text_ranges( indoc! {" one @@ -435,10 +439,12 @@ fn test_clone(cx: &mut gpui::AppContext) { "}, true, ); - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple(&text, cx); + cx.update(|cx| cx.set_global(Settings::test(cx))); - let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); + let (_, editor) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple(&text, cx); + build_editor(buffer, cx) + }); editor.update(cx, |editor, cx| { editor.change_selections(None, cx, |s| s.select_ranges(selection_ranges.clone())); @@ -470,8 +476,8 @@ fn test_clone(cx: &mut gpui::AppContext) { snapshot.folds_in_range(0..text.len()).collect::>(), ); assert_set_eq!( - cloned_editor.read(cx).selections.ranges::(cx), - editor.read(cx).selections.ranges(cx) + cloned_editor.read_with(cx, |editor, cx| editor.selections.ranges::(cx)), + editor.read_with(cx, |editor, cx| editor.selections.ranges(cx)) ); assert_set_eq!( cloned_editor.update(cx, |e, cx| e.selections.display_ranges(cx)), @@ -480,19 +486,19 @@ fn test_clone(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_navigation_history(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); +fn test_navigation_history(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); cx.set_global(DragAndDrop::::default()); use workspace::item::Item; - let (_, pane) = cx.add_window(Default::default(), |cx| Pane::new(0, None, || &[], cx)); - let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx); + let (_, pane) = cx.add_window(|cx| Pane::new(0, None, || &[], cx)); cx.add_view(&pane, |cx| { + let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx); let mut editor = build_editor(buffer.clone(), cx); let handle = cx.handle(); editor.set_nav_history(Some(pane.read(cx).nav_history_for_item(&handle))); - fn pop_history(editor: &mut Editor, cx: &mut AppContext) -> Option { + fn pop_history(editor: &mut Editor, cx: &mut WindowContext) -> Option { editor.nav_history.as_mut().unwrap().pop_backward(cx) } @@ -590,10 +596,12 @@ fn test_navigation_history(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_cancel(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_cancel(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.begin_selection(DisplayPoint::new(3, 4), false, 1, cx); @@ -630,30 +638,32 @@ fn test_cancel(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_fold_action(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple( - &" - impl Foo { - // Hello! +fn test_fold_action(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple( + &" + impl Foo { + // Hello! - fn a() { - 1 - } + fn a() { + 1 + } - fn b() { - 2 - } + fn b() { + 2 + } - fn c() { - 3 + fn c() { + 3 + } } - } - " - .unindent(), - cx, - ); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx)); + " + .unindent(), + cx, + ); + build_editor(buffer.clone(), cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { @@ -712,25 +722,26 @@ fn test_fold_action(cx: &mut gpui::AppContext) { ); view.unfold_lines(&UnfoldLines, cx); - assert_eq!(view.display_text(cx), buffer.read(cx).read(cx).text()); + assert_eq!(view.display_text(cx), view.buffer.read(cx).read(cx).text()); }); } #[gpui::test] -fn test_move_cursor(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx)); - - buffer.update(cx, |buffer, cx| { - buffer.edit( - vec![ - (Point::new(1, 0)..Point::new(1, 0), "\t"), - (Point::new(1, 1)..Point::new(1, 1), "\t"), - ], - None, - cx, - ); +fn test_move_cursor(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx); + buffer.update(cx, |buffer, cx| { + buffer.edit( + vec![ + (Point::new(1, 0)..Point::new(1, 0), "\t"), + (Point::new(1, 1)..Point::new(1, 1), "\t"), + ], + None, + cx, + ); + }); + build_editor(buffer.clone(), cx) }); view.update(cx, |view, cx| { @@ -793,10 +804,12 @@ fn test_move_cursor(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_move_cursor_multibyte(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx)); +fn test_move_cursor_multibyte(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx); + build_editor(buffer.clone(), cx) + }); assert_eq!('ⓐ'.len_utf8(), 3); assert_eq!('α'.len_utf8(), 2); @@ -895,10 +908,12 @@ fn test_move_cursor_multibyte(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_move_cursor_different_line_lengths(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx)); +fn test_move_cursor_different_line_lengths(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx); + build_editor(buffer.clone(), cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([empty_range(0, "ⓐⓑⓒⓓⓔ".len())]); @@ -942,10 +957,12 @@ fn test_move_cursor_different_line_lengths(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_beginning_end_of_line(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("abc\n def", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_beginning_end_of_line(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("abc\n def", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -1102,10 +1119,12 @@ fn test_beginning_end_of_line(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_prev_next_word_boundary(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("use std::str::{foo, bar}\n\n {baz.qux()}", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_prev_next_word_boundary(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("use std::str::{foo, bar}\n\n {baz.qux()}", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -1151,10 +1170,12 @@ fn test_prev_next_word_boundary(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("use one::{\n two::three::four::five\n};", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("use one::{\n two::three::four::five\n};", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.set_wrap_width(Some(140.), cx); @@ -1330,10 +1351,12 @@ async fn test_delete_to_beginning_of_line(cx: &mut gpui::TestAppContext) { } #[gpui::test] -fn test_delete_to_word_boundary(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("one two three four", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx)); +fn test_delete_to_word_boundary(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("one two three four", cx); + build_editor(buffer.clone(), cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { @@ -1345,10 +1368,9 @@ fn test_delete_to_word_boundary(cx: &mut gpui::AppContext) { ]) }); view.delete_to_previous_word_start(&DeleteToPreviousWordStart, cx); + assert_eq!(view.buffer.read(cx).read(cx).text(), "e two te four"); }); - assert_eq!(buffer.read(cx).read(cx).text(), "e two te four"); - view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -1359,16 +1381,17 @@ fn test_delete_to_word_boundary(cx: &mut gpui::AppContext) { ]) }); view.delete_to_next_word_end(&DeleteToNextWordEnd, cx); + assert_eq!(view.buffer.read(cx).read(cx).text(), "e t te our"); }); - - assert_eq!(buffer.read(cx).read(cx).text(), "e t te our"); } #[gpui::test] -fn test_newline(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("aaaa\n bbbb\n", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx)); +fn test_newline(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("aaaa\n bbbb\n", cx); + build_editor(buffer.clone(), cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { @@ -1385,24 +1408,23 @@ fn test_newline(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_newline_with_old_selections(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple( - " - a - b( - X - ) - c( - X - ) - " - .unindent() - .as_str(), - cx, - ); - - let (_, editor) = cx.add_window(Default::default(), |cx| { +fn test_newline_with_old_selections(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, editor) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple( + " + a + b( + X + ) + c( + X + ) + " + .unindent() + .as_str(), + cx, + ); let mut editor = build_editor(buffer.clone(), cx); editor.change_selections(None, cx, |s| { s.select_ranges([ @@ -1413,28 +1435,27 @@ fn test_newline_with_old_selections(cx: &mut gpui::AppContext) { editor }); - // Edit the buffer directly, deleting ranges surrounding the editor's selections - buffer.update(cx, |buffer, cx| { - buffer.edit( - [ - (Point::new(1, 2)..Point::new(3, 0), ""), - (Point::new(4, 2)..Point::new(6, 0), ""), - ], - None, - cx, - ); - assert_eq!( - buffer.read(cx).text(), - " - a - b() - c() - " - .unindent() - ); - }); - editor.update(cx, |editor, cx| { + // Edit the buffer directly, deleting ranges surrounding the editor's selections + editor.buffer.update(cx, |buffer, cx| { + buffer.edit( + [ + (Point::new(1, 2)..Point::new(3, 0), ""), + (Point::new(4, 2)..Point::new(6, 0), ""), + ], + None, + cx, + ); + assert_eq!( + buffer.read(cx).text(), + " + a + b() + c() + " + .unindent() + ); + }); assert_eq!( editor.selections.ranges(cx), &[ @@ -1517,22 +1538,21 @@ async fn test_newline_below(cx: &mut gpui::TestAppContext) { } #[gpui::test] -fn test_insert_with_old_selections(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("a( X ), b( Y ), c( Z )", cx); - let (_, editor) = cx.add_window(Default::default(), |cx| { +fn test_insert_with_old_selections(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, editor) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("a( X ), b( Y ), c( Z )", cx); let mut editor = build_editor(buffer.clone(), cx); editor.change_selections(None, cx, |s| s.select_ranges([3..4, 11..12, 19..20])); editor }); - // Edit the buffer directly, deleting ranges surrounding the editor's selections - buffer.update(cx, |buffer, cx| { - buffer.edit([(2..5, ""), (10..13, ""), (18..21, "")], None, cx); - assert_eq!(buffer.read(cx).text(), "a(), b(), c()".unindent()); - }); - editor.update(cx, |editor, cx| { + // Edit the buffer directly, deleting ranges surrounding the editor's selections + editor.buffer.update(cx, |buffer, cx| { + buffer.edit([(2..5, ""), (10..13, ""), (18..21, "")], None, cx); + assert_eq!(buffer.read(cx).text(), "a(), b(), c()".unindent()); + }); assert_eq!(editor.selections.ranges(cx), &[2..2, 7..7, 12..12],); editor.insert("Z", cx); @@ -1836,24 +1856,26 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut gpui::TestAppContext) { } #[gpui::test] -fn test_indent_outdent_with_excerpts(cx: &mut gpui::AppContext) { - cx.set_global( - Settings::test(cx) - .with_language_defaults( - "TOML", - EditorSettings { - tab_size: Some(2.try_into().unwrap()), - ..Default::default() - }, - ) - .with_language_defaults( - "Rust", - EditorSettings { - tab_size: Some(4.try_into().unwrap()), - ..Default::default() - }, - ), - ); +fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) { + cx.update(|cx| { + cx.set_global( + Settings::test(cx) + .with_language_defaults( + "TOML", + EditorSettings { + tab_size: Some(2.try_into().unwrap()), + ..Default::default() + }, + ) + .with_language_defaults( + "Rust", + EditorSettings { + tab_size: Some(4.try_into().unwrap()), + ..Default::default() + }, + ), + ); + }); let toml_language = Arc::new(Language::new( LanguageConfig { name: "TOML".into(), @@ -1895,7 +1917,7 @@ fn test_indent_outdent_with_excerpts(cx: &mut gpui::AppContext) { multibuffer }); - cx.add_window(Default::default(), |cx| { + cx.add_window(|cx| { let mut editor = build_editor(multibuffer, cx); assert_eq!( @@ -2022,10 +2044,12 @@ async fn test_delete(cx: &mut gpui::TestAppContext) { } #[gpui::test] -fn test_delete_line(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_delete_line(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -2045,9 +2069,11 @@ fn test_delete_line(cx: &mut gpui::AppContext) { ); }); - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)]) @@ -2062,10 +2088,12 @@ fn test_delete_line(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_duplicate_line(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_duplicate_line(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -2088,8 +2116,10 @@ fn test_duplicate_line(cx: &mut gpui::AppContext) { ); }); - let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -2110,10 +2140,12 @@ fn test_duplicate_line(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_move_line_up_down(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_move_line_up_down(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.fold_ranges( vec![ @@ -2206,12 +2238,14 @@ fn test_move_line_up_down(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_move_line_up_down_with_blocks(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx); - let snapshot = buffer.read(cx).snapshot(cx); - let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_move_line_up_down_with_blocks(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, editor) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx); + build_editor(buffer, cx) + }); editor.update(cx, |editor, cx| { + let snapshot = editor.buffer.read(cx).snapshot(cx); editor.insert_blocks( [BlockProperties { style: BlockStyle::Fixed, @@ -2230,11 +2264,11 @@ fn test_move_line_up_down_with_blocks(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_transpose(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); +fn test_transpose(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); _ = cx - .add_window(Default::default(), |cx| { + .add_window(|cx| { let mut editor = build_editor(MultiBuffer::build_simple("abc", cx), cx); editor.change_selections(None, cx, |s| s.select_ranges([1..1])); @@ -2255,7 +2289,7 @@ fn test_transpose(cx: &mut gpui::AppContext) { .1; _ = cx - .add_window(Default::default(), |cx| { + .add_window(|cx| { let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx); editor.change_selections(None, cx, |s| s.select_ranges([3..3])); @@ -2281,7 +2315,7 @@ fn test_transpose(cx: &mut gpui::AppContext) { .1; _ = cx - .add_window(Default::default(), |cx| { + .add_window(|cx| { let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx); editor.change_selections(None, cx, |s| s.select_ranges([1..1, 2..2, 4..4])); @@ -2310,7 +2344,7 @@ fn test_transpose(cx: &mut gpui::AppContext) { .1; _ = cx - .add_window(Default::default(), |cx| { + .add_window(|cx| { let mut editor = build_editor(MultiBuffer::build_simple("🍐🏀✋", cx), cx); editor.change_selections(None, cx, |s| s.select_ranges([4..4])); @@ -2524,10 +2558,12 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) { } #[gpui::test] -fn test_select_all(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("abc\nde\nfgh", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_select_all(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("abc\nde\nfgh", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.select_all(&SelectAll, cx); assert_eq!( @@ -2538,10 +2574,12 @@ fn test_select_all(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_select_line(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple(&sample_text(6, 5, 'a'), cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_select_line(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple(&sample_text(6, 5, 'a'), cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { s.select_display_ranges([ @@ -2582,10 +2620,12 @@ fn test_select_line(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_split_selection_into_lines(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple(&sample_text(9, 5, 'a'), cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_split_selection_into_lines(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple(&sample_text(9, 5, 'a'), cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.fold_ranges( vec![ @@ -2650,10 +2690,12 @@ fn test_split_selection_into_lines(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_add_selection_above_below(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("abc\ndefghi\n\njk\nlmno\n", cx); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx)); +fn test_add_selection_above_below(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, view) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("abc\ndefghi\n\njk\nlmno\n", cx); + build_editor(buffer, cx) + }); view.update(cx, |view, cx| { view.change_selections(None, cx, |s| { @@ -4928,8 +4970,8 @@ async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) { } #[gpui::test] -fn test_editing_disjoint_excerpts(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); +fn test_editing_disjoint_excerpts(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx)); let multibuffer = cx.add_model(|cx| { let mut multibuffer = MultiBuffer::new(0); @@ -4947,12 +4989,11 @@ fn test_editing_disjoint_excerpts(cx: &mut gpui::AppContext) { ], cx, ); + assert_eq!(multibuffer.read(cx).text(), "aaaa\nbbbb"); multibuffer }); - assert_eq!(multibuffer.read(cx).read(cx).text(), "aaaa\nbbbb"); - - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(multibuffer, cx)); + let (_, view) = cx.add_window(|cx| build_editor(multibuffer, cx)); view.update(cx, |view, cx| { assert_eq!(view.text(cx), "aaaa\nbbbb"); view.change_selections(None, cx, |s| { @@ -4975,8 +5016,8 @@ fn test_editing_disjoint_excerpts(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_editing_overlapping_excerpts(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); +fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); let markers = vec![('[', ']').into(), ('(', ')').into()]; let (initial_text, mut excerpt_ranges) = marked_text_ranges_by( indoc! {" @@ -5000,7 +5041,7 @@ fn test_editing_overlapping_excerpts(cx: &mut gpui::AppContext) { multibuffer }); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(multibuffer, cx)); + let (_, view) = cx.add_window(|cx| build_editor(multibuffer, cx)); view.update(cx, |view, cx| { let (expected_text, selection_ranges) = marked_text_ranges( indoc! {" @@ -5048,8 +5089,8 @@ fn test_editing_overlapping_excerpts(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_refresh_selections(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); +fn test_refresh_selections(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx)); let mut excerpt1_id = None; let multibuffer = cx.add_model(|cx| { @@ -5071,13 +5112,11 @@ fn test_refresh_selections(cx: &mut gpui::AppContext) { ) .into_iter() .next(); + assert_eq!(multibuffer.read(cx).text(), "aaaa\nbbbb\nbbbb\ncccc"); multibuffer }); - assert_eq!( - multibuffer.read(cx).read(cx).text(), - "aaaa\nbbbb\nbbbb\ncccc" - ); - let (_, editor) = cx.add_window(Default::default(), |cx| { + + let (_, editor) = cx.add_window(|cx| { let mut editor = build_editor(multibuffer.clone(), cx); let snapshot = editor.snapshot(cx); editor.change_selections(None, cx, |s| { @@ -5134,8 +5173,8 @@ fn test_refresh_selections(cx: &mut gpui::AppContext) { } #[gpui::test] -fn test_refresh_selections_while_selecting_with_mouse(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); +fn test_refresh_selections_while_selecting_with_mouse(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx)); let mut excerpt1_id = None; let multibuffer = cx.add_model(|cx| { @@ -5157,13 +5196,11 @@ fn test_refresh_selections_while_selecting_with_mouse(cx: &mut gpui::AppContext) ) .into_iter() .next(); + assert_eq!(multibuffer.read(cx).text(), "aaaa\nbbbb\nbbbb\ncccc"); multibuffer }); - assert_eq!( - multibuffer.read(cx).read(cx).text(), - "aaaa\nbbbb\nbbbb\ncccc" - ); - let (_, editor) = cx.add_window(Default::default(), |cx| { + + let (_, editor) = cx.add_window(|cx| { let mut editor = build_editor(multibuffer.clone(), cx); let snapshot = editor.snapshot(cx); editor.begin_selection(Point::new(1, 3).to_display_point(&snapshot), false, 1, cx); @@ -5267,17 +5304,18 @@ async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) { } #[gpui::test] -fn test_highlighted_ranges(cx: &mut gpui::AppContext) { - let buffer = MultiBuffer::build_simple(&sample_text(16, 8, 'a'), cx); - - cx.set_global(Settings::test(cx)); - let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx)); +fn test_highlighted_ranges(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, editor) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple(&sample_text(16, 8, 'a'), cx); + build_editor(buffer.clone(), cx) + }); editor.update(cx, |editor, cx| { struct Type1; struct Type2; - let buffer = buffer.read(cx).snapshot(cx); + let buffer = editor.buffer.read(cx).snapshot(cx); let anchor_range = |range: Range| buffer.anchor_after(range.start)..buffer.anchor_after(range.end); @@ -5761,7 +5799,6 @@ async fn go_to_hunk(deterministic: Arc, cx: &mut gpui::TestAppCon &r#" ˇuse some::modified; - fn main() { println!("hello there"); @@ -5783,7 +5820,6 @@ async fn go_to_hunk(deterministic: Arc, cx: &mut gpui::TestAppCon &r#" use some::modified; - fn main() { ˇ println!("hello there"); @@ -5807,7 +5843,6 @@ async fn go_to_hunk(deterministic: Arc, cx: &mut gpui::TestAppCon &r#" ˇuse some::modified; - fn main() { println!("hello there"); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 7ef3c3e81d..9ec01b938a 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -2493,24 +2493,24 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 { #[cfg(test)] mod tests { - use std::sync::Arc; - use super::*; use crate::{ display_map::{BlockDisposition, BlockProperties}, Editor, MultiBuffer, }; + use gpui::TestAppContext; use settings::Settings; + use std::sync::Arc; use util::test::sample_text; #[gpui::test] - fn test_layout_line_numbers(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx); - let (_, editor) = cx.add_window(Default::default(), |cx| { + fn test_layout_line_numbers(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, editor) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx); Editor::new(EditorMode::Full, buffer, None, None, cx) }); - let element = EditorElement::new(editor.read(cx).style(cx)); + let element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx))); let layouts = editor.update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); @@ -2522,10 +2522,10 @@ mod tests { } #[gpui::test] - fn test_layout_with_placeholder_text_and_blocks(cx: &mut gpui::AppContext) { - cx.set_global(Settings::test(cx)); - let buffer = MultiBuffer::build_simple("", cx); - let (_, editor) = cx.add_window(Default::default(), |cx| { + fn test_layout_with_placeholder_text_and_blocks(cx: &mut TestAppContext) { + cx.update(|cx| cx.set_global(Settings::test(cx))); + let (_, editor) = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("", cx); Editor::new(EditorMode::Full, buffer, None, None, cx) }); @@ -2546,7 +2546,7 @@ mod tests { cx.blur(); }); - let mut element = EditorElement::new(editor.read(cx).style(cx)); + let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx))); let (size, mut state) = editor.update(cx, |editor, cx| { element.layout( SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)), diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs index 9e66fea8df..63d3b49a99 100644 --- a/crates/editor/src/test/editor_test_context.rs +++ b/crates/editor/src/test/editor_test_context.rs @@ -34,11 +34,10 @@ impl<'a> EditorTestContext<'a> { crate::init(cx); let (window_id, editor) = cx.add_window(Default::default(), |cx| { + cx.focus_self(); build_editor(MultiBuffer::build_simple("", cx), cx) }); - editor.update(cx, |_, cx| cx.focus_self()); - (window_id, editor) }); @@ -254,10 +253,10 @@ impl<'a> EditorTestContext<'a> { panic!( indoc! {" {}Editor has unexpected selections. - + Expected selections: {} - + Actual selections: {} "}, diff --git a/crates/feedback/src/feedback_editor.rs b/crates/feedback/src/feedback_editor.rs index 98566a2361..aae8657911 100644 --- a/crates/feedback/src/feedback_editor.rs +++ b/crates/feedback/src/feedback_editor.rs @@ -132,25 +132,18 @@ impl FeedbackEditor { if answer == Some(0) { match FeedbackEditor::submit_feedback(&feedback_text, client, specs).await { - Ok(_) => { - cx.update(|cx| { - this.update(cx, |_, cx| { - cx.dispatch_action(workspace::CloseActiveItem); - }) - }); - } + Ok(_) => this.update(&mut cx, |_, cx| { + cx.dispatch_action(workspace::CloseActiveItem); + }), Err(error) => { log::error!("{}", error); - - cx.update(|cx| { - this.update(cx, |_, cx| { - cx.prompt( - PromptLevel::Critical, - FEEDBACK_SUBMISSION_ERROR_TEXT, - &["OK"], - ); - }) - }); + this.update(&mut cx, |_, cx| { + cx.prompt( + PromptLevel::Critical, + FEEDBACK_SUBMISSION_ERROR_TEXT, + &["OK"], + ); + }) } } } diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index eed96297bb..720e2ec2e4 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -142,12 +142,14 @@ impl Entity for GoToLine { fn release(&mut self, cx: &mut AppContext) { let scroll_position = self.prev_scroll_position.take(); - self.active_editor.update(cx, |editor, cx| { - editor.highlight_rows(None); - if let Some(scroll_position) = scroll_position { - editor.set_scroll_position(scroll_position, cx); - } - }) + cx.update_window(self.active_editor.window_id(), |cx| { + self.active_editor.update(cx, |editor, cx| { + editor.highlight_rows(None); + if let Some(scroll_position) = scroll_position { + editor.set_scroll_position(scroll_position, cx); + } + }) + }); } } diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 6005eea37c..1d50cfac9d 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -937,7 +937,7 @@ impl AppContext { }) } - pub fn subscribe_internal(&mut self, handle: &H, mut callback: F) -> Subscription + fn subscribe_internal(&mut self, handle: &H, mut callback: F) -> Subscription where E: Entity, E::Event: 'static, @@ -1224,19 +1224,28 @@ impl AppContext { T: 'static, F: FnOnce(&mut T, &mut AppContext) -> U, { - self.update(|this| { - let type_id = TypeId::of::(); - if let Some(mut state) = this.globals.remove(&type_id) { - let result = update(state.downcast_mut().unwrap(), this); - this.globals.insert(type_id, state); - this.notify_global(type_id); - result - } else { - panic!("No global added for {}", std::any::type_name::()); - } + self.update(|mut this| { + Self::update_global_internal(&mut this, |global, cx| update(global, cx)) }) } + fn update_global_internal(this: &mut C, update: F) -> U + where + C: DerefMut, + T: 'static, + F: FnOnce(&mut T, &mut C) -> U, + { + let type_id = TypeId::of::(); + if let Some(mut state) = this.globals.remove(&type_id) { + let result = update(state.downcast_mut().unwrap(), this); + this.globals.insert(type_id, state); + this.notify_global(type_id); + result + } else { + panic!("No global added for {}", std::any::type_name::()); + } + } + pub fn clear_globals(&mut self) { self.globals.clear(); } @@ -2714,15 +2723,6 @@ impl<'a, T: Entity> ModelContext<'a, T> { self.app.add_model(build_model) } - pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut T, &mut ModelContext)) { - let handle = self.handle(); - self.app.defer(move |cx| { - handle.update(cx, |model, cx| { - callback(model, cx); - }) - }) - } - pub fn emit(&mut self, payload: T::Event) { self.app.pending_effects.push_back(Effect::Event { entity_id: self.model_id, @@ -3090,21 +3090,17 @@ impl<'a, 'b, 'c, V: View> ViewContext<'a, 'b, 'c, V> { H: Handle, F: 'static + FnMut(&mut V, H, &E::Event, &mut ViewContext), { - let window_id = self.window_id; let subscriber = self.weak_handle(); self.window_context .subscribe_internal(handle, move |emitter, event, cx| { - cx.update_window(window_id, |cx| { - if let Some(subscriber) = subscriber.upgrade(cx) { - subscriber.update(cx, |subscriber, cx| { - callback(subscriber, emitter, event, cx); - }); - true - } else { - false - } - }) - .unwrap_or(false) + if let Some(subscriber) = subscriber.upgrade(cx) { + subscriber.update(cx, |subscriber, cx| { + callback(subscriber, emitter, event, cx); + }); + true + } else { + false + } }) } @@ -3333,15 +3329,9 @@ impl<'a, 'b, 'c, V: View> ViewContext<'a, 'b, 'c, V> { } pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut V, &mut ViewContext)) { - let window_id = self.window_id; let handle = self.handle(); - self.window_context.defer(move |cx| { - cx.update_window(window_id, |cx| { - handle.update(cx, |view, cx| { - callback(view, cx); - }) - }); - }) + self.window_context + .defer(move |cx| handle.update(cx, |view, cx| callback(view, cx))) } pub fn after_window_update( @@ -4651,7 +4641,7 @@ mod tests { } #[crate::test(self)] - fn test_defer_and_after_window_update(cx: &mut AppContext) { + fn test_defer_and_after_window_update(cx: &mut TestAppContext) { struct View { render_count: usize, } @@ -4671,7 +4661,7 @@ mod tests { } } - let (_, view) = cx.add_window(Default::default(), |_| View { render_count: 0 }); + let (_, view) = cx.add_window(|_| View { render_count: 0 }); let called_defer = Rc::new(AtomicBool::new(false)); let called_after_window_update = Rc::new(AtomicBool::new(false)); @@ -4699,11 +4689,11 @@ mod tests { assert!(called_defer.load(SeqCst)); assert!(called_after_window_update.load(SeqCst)); - assert_eq!(view.read(cx).render_count, 3); + assert_eq!(view.read_with(cx, |view, _| view.render_count), 3); } #[crate::test(self)] - fn test_view_handles(cx: &mut AppContext) { + fn test_view_handles(cx: &mut TestAppContext) { struct View { other: Option>, events: Vec, @@ -4738,33 +4728,39 @@ mod tests { } } - let (_, root_view) = cx.add_window(Default::default(), |cx| View::new(None, cx)); + let (_, root_view) = cx.add_window(|cx| View::new(None, cx)); let handle_1 = cx.add_view(&root_view, |cx| View::new(None, cx)); let handle_2 = cx.add_view(&root_view, |cx| View::new(Some(handle_1.clone()), cx)); - assert_eq!(cx.views.len(), 3); + assert_eq!(cx.read(|cx| cx.views.len()), 3); handle_1.update(cx, |view, cx| { view.events.push("updated".into()); cx.emit(1); cx.emit(2); }); - assert_eq!(handle_1.read(cx).events, vec!["updated".to_string()]); - assert_eq!( - handle_2.read(cx).events, - vec![ - "observed event 1".to_string(), - "observed event 2".to_string(), - ] - ); + handle_1.read_with(cx, |view, _| { + assert_eq!(view.events, vec!["updated".to_string()]); + }); + handle_2.read_with(cx, |view, _| { + assert_eq!( + view.events, + vec![ + "observed event 1".to_string(), + "observed event 2".to_string(), + ] + ); + }); handle_2.update(cx, |view, _| { drop(handle_1); view.other.take(); }); - assert_eq!(cx.views.len(), 2); - assert!(cx.subscriptions.is_empty()); - assert!(cx.observations.is_empty()); + cx.read(|cx| { + assert_eq!(cx.views.len(), 2); + assert!(cx.subscriptions.is_empty()); + assert!(cx.observations.is_empty()); + }); } #[crate::test(self)] @@ -4887,14 +4883,14 @@ mod tests { } #[crate::test(self)] - fn test_view_events(cx: &mut AppContext) { + fn test_view_events(cx: &mut TestAppContext) { struct Model; impl Entity for Model { type Event = String; } - let (_, handle_1) = cx.add_window(Default::default(), |_| TestView::default()); + let (_, handle_1) = cx.add_window(|_| TestView::default()); let handle_2 = cx.add_view(&handle_1, |_| TestView::default()); let handle_3 = cx.add_model(|_| Model); @@ -4916,16 +4912,17 @@ mod tests { }); handle_2.update(cx, |_, c| c.emit("7".into())); - assert_eq!(handle_1.read(cx).events, vec!["7"]); + handle_1.read_with(cx, |view, _| assert_eq!(view.events, ["7"])); handle_2.update(cx, |_, c| c.emit("5".into())); - assert_eq!(handle_1.read(cx).events, vec!["7", "5", "5 from inner"]); + handle_1.read_with(cx, |view, _| { + assert_eq!(view.events, ["7", "5", "5 from inner"]) + }); handle_3.update(cx, |_, c| c.emit("9".into())); - assert_eq!( - handle_1.read(cx).events, - vec!["7", "5", "5 from inner", "9"] - ); + handle_1.read_with(cx, |view, _| { + assert_eq!(view.events, ["7", "5", "5 from inner", "9"]) + }); } #[crate::test(self)] @@ -5113,14 +5110,14 @@ mod tests { } #[crate::test(self)] - fn test_dropping_subscribers(cx: &mut AppContext) { + fn test_dropping_subscribers(cx: &mut TestAppContext) { struct Model; impl Entity for Model { type Event = (); } - let (_, root_view) = cx.add_window(Default::default(), |_| TestView::default()); + let (_, root_view) = cx.add_window(|_| TestView::default()); let observing_view = cx.add_view(&root_view, |_| TestView::default()); let emitting_view = cx.add_view(&root_view, |_| TestView::default()); let observing_model = cx.add_model(|_| Model); @@ -5165,7 +5162,7 @@ mod tests { } #[crate::test(self)] - fn test_observe_and_notify_from_view(cx: &mut AppContext) { + fn test_observe_and_notify_from_view(cx: &mut TestAppContext) { #[derive(Default)] struct Model { state: String, @@ -5175,7 +5172,7 @@ mod tests { type Event = (); } - let (_, view) = cx.add_window(Default::default(), |_| TestView::default()); + let (_, view) = cx.add_window(|_| TestView::default()); let model = cx.add_model(|_| Model { state: "old-state".into(), }); @@ -5191,7 +5188,7 @@ mod tests { model.state = "new-state".into(); cx.notify(); }); - assert_eq!(view.read(cx).events, vec!["new-state"]); + view.read_with(cx, |view, _| assert_eq!(view.events, ["new-state"])); } #[crate::test(self)] @@ -5216,14 +5213,14 @@ mod tests { } #[crate::test(self)] - fn test_notify_and_drop_observe_subscription_in_same_update_cycle(cx: &mut AppContext) { + fn test_notify_and_drop_observe_subscription_in_same_update_cycle(cx: &mut TestAppContext) { struct Model; impl Entity for Model { type Event = (); } let model = cx.add_model(|_| Model); - let (_, view) = cx.add_window(Default::default(), |_| TestView::default()); + let (_, view) = cx.add_window(|_| TestView::default()); view.update(cx, |_, cx| { model.update(cx, |_, cx| cx.notify()); @@ -5236,19 +5233,18 @@ mod tests { for _ in 0..3 { model.update(cx, |_, cx| cx.notify()); } - - assert_eq!(view.read(cx).events, Vec::::new()); + view.read_with(cx, |view, _| assert_eq!(view.events, Vec::<&str>::new())); } #[crate::test(self)] - fn test_dropping_observers(cx: &mut AppContext) { + fn test_dropping_observers(cx: &mut TestAppContext) { struct Model; impl Entity for Model { type Event = (); } - let (_, root_view) = cx.add_window(Default::default(), |_| TestView::default()); + let (_, root_view) = cx.add_window(|_| TestView::default()); let observing_view = cx.add_view(&root_view, |_| TestView::default()); let observing_model = cx.add_model(|_| Model); let observed_model = cx.add_model(|_| Model); @@ -5269,7 +5265,7 @@ mod tests { } #[crate::test(self)] - fn test_dropping_subscriptions_during_callback(cx: &mut AppContext) { + fn test_dropping_subscriptions_during_callback(cx: &mut TestAppContext) { struct Model; impl Entity for Model { @@ -5371,7 +5367,7 @@ mod tests { } } - let (_, root_view) = cx.add_window(Default::default(), |_| View); + let (_, root_view) = cx.add_window(|_| View); let observing_view = cx.add_view(&root_view, |_| View); let observed_view = cx.add_view(&root_view, |_| View); @@ -5410,13 +5406,15 @@ mod tests { } })); - cx.default_global::<()>(); - cx.set_global(()); + cx.update(|cx| { + cx.default_global::<()>(); + cx.set_global(()); + }); assert_eq!(*observation_count.borrow(), 1); } #[crate::test(self)] - fn test_focus(cx: &mut AppContext) { + fn test_focus(cx: &mut TestAppContext) { struct View { name: String, events: Arc>>, @@ -5449,7 +5447,7 @@ mod tests { } let view_events: Arc>> = Default::default(); - let (window_id, view_1) = cx.add_window(Default::default(), |_| View { + let (window_id, view_1) = cx.add_window(|_| View { events: view_events.clone(), name: "view 1".to_string(), }); @@ -6295,7 +6293,7 @@ mod tests { } #[crate::test(self)] - fn test_child_view(cx: &mut AppContext) { + fn test_child_view(cx: &mut TestAppContext) { struct Child { rendered: Rc>, dropped: Rc>, @@ -6346,7 +6344,7 @@ mod tests { let child_rendered = Rc::new(Cell::new(false)); let child_dropped = Rc::new(Cell::new(false)); - let (_, root_view) = cx.add_window(Default::default(), |cx| Parent { + let (_, root_view) = cx.add_window(|cx| Parent { child: Some(cx.add_view(|_| Child { rendered: child_rendered.clone(), dropped: child_dropped.clone(), diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index b32bbc2fad..ded009f4ba 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -1,4 +1,5 @@ use std::{ + any::Any, cell::RefCell, mem, path::PathBuf, @@ -22,8 +23,8 @@ use crate::{ platform, platform::{Event, InputHandler, KeyDownEvent, Platform}, Action, AnyViewHandle, AppContext, Entity, FontCache, Handle, ModelContext, ModelHandle, - ReadModelWith, ReadViewWith, Task, UpdateModel, UpdateView, View, ViewContext, ViewHandle, - WeakHandle, WindowContext, + ReadModelWith, ReadViewWith, Subscription, Task, UpdateModel, UpdateView, View, ViewContext, + ViewHandle, WeakHandle, WindowContext, }; use collections::BTreeMap; @@ -160,6 +161,26 @@ impl TestAppContext { self.cx.borrow_mut().add_view(parent_handle, build_view) } + pub fn observe_global(&mut self, callback: F) -> Subscription + where + E: Any, + F: 'static + FnMut(&mut AppContext), + { + self.cx.borrow_mut().observe_global::(callback) + } + + pub fn set_global(&mut self, state: T) { + self.cx.borrow_mut().set_global(state); + } + + pub fn subscribe_global(&mut self, callback: F) -> Subscription + where + E: Any, + F: 'static + FnMut(&E, &mut AppContext), + { + self.cx.borrow_mut().subscribe_global(callback) + } + pub fn window_ids(&self) -> Vec { self.cx.borrow().window_ids().collect() } diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 106ec2b32e..4b053a8a09 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -13,10 +13,11 @@ use crate::{ }, text_layout::TextLayoutCache, util::post_inc, - Action, AnyView, AnyViewHandle, AnyWeakViewHandle, AppContext, Drawable, Effect, Entity, - ModelContext, ModelHandle, MouseRegion, MouseRegionId, ParentId, ReadModel, ReadView, - SceneBuilder, Subscription, UpdateModel, UpdateView, UpgradeViewHandle, View, ViewContext, - ViewHandle, WeakViewHandle, WindowInvalidation, + Action, AnyModelHandle, AnyView, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, + AppContext, Drawable, Effect, Entity, Handle, ModelContext, ModelHandle, MouseRegion, + MouseRegionId, ParentId, ReadModel, ReadView, SceneBuilder, Subscription, UpdateModel, + UpdateView, UpgradeModelHandle, UpgradeViewHandle, View, ViewContext, ViewHandle, + WeakModelHandle, WeakViewHandle, WindowInvalidation, }; use anyhow::{anyhow, bail, Result}; use collections::{HashMap, HashSet}; @@ -175,6 +176,23 @@ impl UpdateView for WindowContext<'_, '_> { } } +impl UpgradeModelHandle for WindowContext<'_, '_> { + fn upgrade_model_handle( + &self, + handle: &WeakModelHandle, + ) -> Option> { + self.app_context.upgrade_model_handle(handle) + } + + fn model_handle_is_upgradable(&self, handle: &WeakModelHandle) -> bool { + self.app_context.model_handle_is_upgradable(handle) + } + + fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option { + self.app_context.upgrade_any_model_handle(handle) + } +} + impl UpgradeViewHandle for WindowContext<'_, '_> { fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { self.app_context.upgrade_view_handle(handle) @@ -239,6 +257,49 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { Some(result) } + pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut WindowContext)) { + let window_id = self.window_id; + self.app_context.defer(move |cx| { + cx.update_window(window_id, |cx| callback(cx)); + }) + } + + pub fn update_global(&mut self, update: F) -> U + where + T: 'static, + F: FnOnce(&mut T, &mut Self) -> U, + { + AppContext::update_global_internal(self, |global, cx| update(global, cx)) + } + + pub fn subscribe(&mut self, handle: &H, mut callback: F) -> Subscription + where + E: Entity, + E::Event: 'static, + H: Handle, + F: 'static + FnMut(H, &E::Event, &mut WindowContext), + { + self.subscribe_internal(handle, move |emitter, event, cx| { + callback(emitter, event, cx); + true + }) + } + + pub fn subscribe_internal(&mut self, handle: &H, mut callback: F) -> Subscription + where + E: Entity, + E::Event: 'static, + H: Handle, + F: 'static + FnMut(H, &E::Event, &mut WindowContext) -> bool, + { + let window_id = self.window_id; + self.app_context + .subscribe_internal(handle, move |emitter, event, cx| { + cx.update_window(window_id, |cx| callback(emitter, event, cx)) + .unwrap_or(false) + }) + } + pub(crate) fn observe_window_activation(&mut self, callback: F) -> Subscription where F: 'static + FnMut(bool, &mut WindowContext) -> bool, diff --git a/crates/gpui_macros/src/gpui_macros.rs b/crates/gpui_macros/src/gpui_macros.rs index 42cdb66ee3..ca15fa14a2 100644 --- a/crates/gpui_macros/src/gpui_macros.rs +++ b/crates/gpui_macros/src/gpui_macros.rs @@ -174,23 +174,60 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { } } } else { + // Pass to the test function the number of app contexts that it needs, + // based on its parameter list. + let mut cx_vars = proc_macro2::TokenStream::new(); + let mut cx_teardowns = proc_macro2::TokenStream::new(); let mut inner_fn_args = proc_macro2::TokenStream::new(); - for arg in inner_fn.sig.inputs.iter() { + for (ix, arg) in inner_fn.sig.inputs.iter().enumerate() { if let FnArg::Typed(arg) = arg { if let Type::Path(ty) = &*arg.ty { let last_segment = ty.path.segments.last(); if let Some("StdRng") = last_segment.map(|s| s.ident.to_string()).as_deref() { inner_fn_args.extend(quote!(rand::SeedableRng::seed_from_u64(seed),)); + continue; + } + } else if let Type::Reference(ty) = &*arg.ty { + if let Type::Path(ty) = &*ty.elem { + let last_segment = ty.path.segments.last(); + match last_segment.map(|s| s.ident.to_string()).as_deref() { + Some("AppContext") => { + inner_fn_args.extend(quote!(cx,)); + continue; + } + Some("TestAppContext") => { + let first_entity_id = ix * 100_000; + let cx_varname = format_ident!("cx_{}", ix); + cx_vars.extend(quote!( + let mut #cx_varname = #namespace::TestAppContext::new( + foreground_platform.clone(), + cx.platform().clone(), + deterministic.build_foreground(#ix), + deterministic.build_background(), + cx.font_cache().clone(), + cx.leak_detector(), + #first_entity_id, + stringify!(#outer_fn_name).to_string(), + ); + )); + cx_teardowns.extend(quote!( + #cx_varname.update(|cx| cx.remove_all_windows()); + deterministic.run_until_parked(); + #cx_varname.update(|cx| cx.clear_globals()); + )); + inner_fn_args.extend(quote!(&mut #cx_varname,)); + continue; + } + _ => {} + } } - } else { - inner_fn_args.extend(quote!(cx,)); } - } else { - return TokenStream::from( - syn::Error::new_spanned(arg, "invalid argument").into_compile_error(), - ); } + + return TokenStream::from( + syn::Error::new_spanned(arg, "invalid argument").into_compile_error(), + ); } parse_quote! { @@ -203,7 +240,11 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { #starting_seed as u64, #max_retries, #detect_nondeterminism, - &mut |cx, _, _, seed| #inner_fn_name(#inner_fn_args), + &mut |cx, foreground_platform, deterministic, seed| { + #cx_vars + #inner_fn_name(#inner_fn_args); + #cx_teardowns + }, #on_failure_fn_name, stringify!(#outer_fn_name).to_string(), ); diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index eeb7a19257..7172eb5035 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -5,7 +5,7 @@ use editor::{ use fuzzy::StringMatch; use gpui::{ actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, AppContext, Entity, - MouseState, Task, View, ViewContext, ViewHandle, + MouseState, Task, View, ViewContext, ViewHandle, WindowContext, }; use language::Outline; use ordered_float::OrderedFloat; @@ -39,7 +39,9 @@ impl Entity for OutlineView { type Event = Event; fn release(&mut self, cx: &mut AppContext) { - self.restore_active_editor(cx); + cx.update_window(self.active_editor.window_id(), |cx| { + self.restore_active_editor(cx); + }); } } @@ -100,7 +102,7 @@ impl OutlineView { } } - fn restore_active_editor(&mut self, cx: &mut AppContext) { + fn restore_active_editor(&mut self, cx: &mut WindowContext) { self.active_editor.update(cx, |editor, cx| { editor.highlight_rows(None); if let Some(scroll_position) = self.prev_scroll_position { diff --git a/crates/vim/src/editor_events.rs b/crates/vim/src/editor_events.rs index dc253254cc..658f80f323 100644 --- a/crates/vim/src/editor_events.rs +++ b/crates/vim/src/editor_events.rs @@ -11,13 +11,9 @@ pub fn init(cx: &mut AppContext) { fn focused(EditorFocused(editor): &EditorFocused, cx: &mut AppContext) { Vim::update(cx, |vim, cx| { - if let Some(previously_active_editor) = vim - .active_editor - .as_ref() - .and_then(|editor| editor.upgrade(cx)) - { - vim.unhook_vim_settings(previously_active_editor, cx); - } + vim.update_active_editor(cx, |previously_active_editor, cx| { + Vim::unhook_vim_settings(previously_active_editor, cx); + }); vim.active_editor = Some(editor.downgrade()); vim.editor_subscription = Some(cx.subscribe(editor, |editor, event, cx| match event { @@ -55,7 +51,10 @@ fn blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut AppContext) { vim.active_editor = None; } } - vim.unhook_vim_settings(editor.clone(), cx); + + cx.update_window(editor.window_id(), |cx| { + editor.update(cx, |editor, cx| Vim::unhook_vim_settings(editor, cx)) + }); }) } diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index 5f6c6435df..f9f72b7c37 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -15,8 +15,7 @@ use std::sync::Arc; use collections::CommandPaletteFilter; use editor::{Bias, Cancel, Editor, EditorMode}; use gpui::{ - actions, impl_actions, AppContext, Subscription, ViewContext, ViewHandle, WeakViewHandle, - WindowContext, + actions, impl_actions, AppContext, Subscription, ViewContext, WeakViewHandle, WindowContext, }; use language::CursorShape; use motion::Motion; @@ -148,10 +147,8 @@ impl Vim { cx: &mut AppContext, update: impl FnOnce(&mut Editor, &mut ViewContext) -> S, ) -> Option { - self.active_editor - .clone() - .and_then(|ae| ae.upgrade(cx)) - .map(|ae| ae.update(cx, update)) + let editor = self.active_editor.clone()?.upgrade(cx)?; + cx.update_window(editor.window_id(), |cx| editor.update(cx, update)) } fn switch_mode(&mut self, mode: Mode, leave_selections: bool, cx: &mut AppContext) { @@ -166,27 +163,19 @@ impl Vim { } // Adjust selections - if let Some(editor) = self - .active_editor - .as_ref() - .and_then(|editor| editor.upgrade(cx)) - { - editor.update(cx, |editor, cx| { - editor.change_selections(None, cx, |s| { - s.move_with(|map, selection| { - if self.state.empty_selections_only() { - let new_head = map.clip_point(selection.head(), Bias::Left); - selection.collapse_to(new_head, selection.goal) - } else { - selection.set_head( - map.clip_point(selection.head(), Bias::Left), - selection.goal, - ); - } - }); - }) + self.update_active_editor(cx, |editor, cx| { + editor.change_selections(None, cx, |s| { + s.move_with(|map, selection| { + if self.state.empty_selections_only() { + let new_head = map.clip_point(selection.head(), Bias::Left); + selection.collapse_to(new_head, selection.goal) + } else { + selection + .set_head(map.clip_point(selection.head(), Bias::Left), selection.goal); + } + }); }) - } + }); } fn push_operator(&mut self, operator: Operator, cx: &mut AppContext) { @@ -272,33 +261,25 @@ impl Vim { } }); - if let Some(editor) = self - .active_editor - .as_ref() - .and_then(|editor| editor.upgrade(cx)) - { - if self.enabled && editor.read(cx).mode() == EditorMode::Full { - editor.update(cx, |editor, cx| { - editor.set_cursor_shape(cursor_shape, cx); - editor.set_clip_at_line_ends(state.clip_at_line_end(), cx); - editor.set_input_enabled(!state.vim_controlled()); - editor.selections.line_mode = matches!(state.mode, Mode::Visual { line: true }); - let context_layer = state.keymap_context_layer(); - editor.set_keymap_context_layer::(context_layer); - }); + self.update_active_editor(cx, |editor, cx| { + if self.enabled && editor.mode() == EditorMode::Full { + editor.set_cursor_shape(cursor_shape, cx); + editor.set_clip_at_line_ends(state.clip_at_line_end(), cx); + editor.set_input_enabled(!state.vim_controlled()); + editor.selections.line_mode = matches!(state.mode, Mode::Visual { line: true }); + let context_layer = state.keymap_context_layer(); + editor.set_keymap_context_layer::(context_layer); } else { - self.unhook_vim_settings(editor, cx); + Self::unhook_vim_settings(editor, cx); } - } - } - - fn unhook_vim_settings(&self, editor: ViewHandle, cx: &mut AppContext) { - editor.update(cx, |editor, cx| { - editor.set_cursor_shape(CursorShape::Bar, cx); - editor.set_clip_at_line_ends(false, cx); - editor.set_input_enabled(true); - editor.selections.line_mode = false; - editor.remove_keymap_context_layer::(); }); } + + fn unhook_vim_settings(editor: &mut Editor, cx: &mut ViewContext) { + editor.set_cursor_shape(CursorShape::Bar, cx); + editor.set_clip_at_line_ends(false, cx); + editor.set_input_enabled(true); + editor.selections.line_mode = false; + editor.remove_keymap_context_layer::(); + } } diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 32e414aa3a..c1840cf34f 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -171,7 +171,7 @@ pub trait ItemHandle: 'static + fmt::Debug { fn subscribe_to_item_events( &self, cx: &mut WindowContext, - handler: Box, + handler: Box, ) -> gpui::Subscription; fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option>; fn tab_content( @@ -254,7 +254,7 @@ impl ItemHandle for ViewHandle { fn subscribe_to_item_events( &self, cx: &mut WindowContext, - handler: Box, + handler: Box, ) -> gpui::Subscription { cx.subscribe(self, move |_, event, cx| { for item_event in T::to_item_events(event) { @@ -677,7 +677,7 @@ pub trait FollowableItem: Item { pub trait FollowableItemHandle: ItemHandle { fn remote_id(&self, client: &Arc, cx: &AppContext) -> Option; - fn set_leader_replica_id(&self, leader_replica_id: Option, cx: &mut AppContext); + fn set_leader_replica_id(&self, leader_replica_id: Option, cx: &mut WindowContext); fn to_state_proto(&self, cx: &AppContext) -> Option; fn add_event_to_update_proto( &self, @@ -689,7 +689,7 @@ pub trait FollowableItemHandle: ItemHandle { &self, project: &ModelHandle, message: proto::update_view::Variant, - cx: &mut AppContext, + cx: &mut WindowContext, ) -> Task>; fn should_unfollow_on_event(&self, event: &dyn Any, cx: &AppContext) -> bool; } @@ -704,7 +704,7 @@ impl FollowableItemHandle for ViewHandle { }) } - fn set_leader_replica_id(&self, leader_replica_id: Option, cx: &mut AppContext) { + fn set_leader_replica_id(&self, leader_replica_id: Option, cx: &mut WindowContext) { self.update(cx, |this, cx| { this.set_leader_replica_id(leader_replica_id, cx) }) @@ -731,7 +731,7 @@ impl FollowableItemHandle for ViewHandle { &self, project: &ModelHandle, message: proto::update_view::Variant, - cx: &mut AppContext, + cx: &mut WindowContext, ) -> Task> { self.update(cx, |this, cx| this.apply_update_proto(project, message, cx)) } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 7f937d9aed..c05345860f 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1890,15 +1890,15 @@ fn render_tab_bar_button( } impl ItemNavHistory { - pub fn push(&self, data: Option, cx: &mut AppContext) { + pub fn push(&self, data: Option, cx: &mut WindowContext) { self.history.borrow_mut().push(data, self.item.clone(), cx); } - pub fn pop_backward(&self, cx: &mut AppContext) -> Option { + pub fn pop_backward(&self, cx: &mut WindowContext) -> Option { self.history.borrow_mut().pop(NavigationMode::GoingBack, cx) } - pub fn pop_forward(&self, cx: &mut AppContext) -> Option { + pub fn pop_forward(&self, cx: &mut WindowContext) -> Option { self.history .borrow_mut() .pop(NavigationMode::GoingForward, cx) @@ -1918,7 +1918,7 @@ impl NavHistory { self.mode = NavigationMode::Normal; } - fn pop(&mut self, mode: NavigationMode, cx: &mut AppContext) -> Option { + fn pop(&mut self, mode: NavigationMode, cx: &mut WindowContext) -> Option { let entry = match mode { NavigationMode::Normal | NavigationMode::Disabled | NavigationMode::ClosingItem => { return None @@ -1938,7 +1938,7 @@ impl NavHistory { &mut self, data: Option, item: Rc, - cx: &mut AppContext, + cx: &mut WindowContext, ) { match self.mode { NavigationMode::Disabled => {} @@ -1983,7 +1983,7 @@ impl NavHistory { self.did_update(cx); } - fn did_update(&self, cx: &mut AppContext) { + fn did_update(&self, cx: &mut WindowContext) { if let Some(pane) = self.pane.upgrade(cx) { cx.defer(move |cx| pane.update(cx, |pane, cx| pane.history_updated(cx))); } diff --git a/crates/workspace/src/searchable.rs b/crates/workspace/src/searchable.rs index c72023b4d4..7e3f7227b0 100644 --- a/crates/workspace/src/searchable.rs +++ b/crates/workspace/src/searchable.rs @@ -2,7 +2,7 @@ use std::any::Any; use gpui::{ AnyViewHandle, AnyWeakViewHandle, AppContext, Subscription, Task, ViewContext, ViewHandle, - WeakViewHandle, + WeakViewHandle, WindowContext, }; use project::search::SearchQuery; @@ -90,29 +90,34 @@ pub trait SearchableItemHandle: ItemHandle { fn supported_options(&self) -> SearchOptions; fn subscribe_to_search_events( &self, - cx: &mut AppContext, - handler: Box, + cx: &mut WindowContext, + handler: Box, ) -> Subscription; - fn clear_matches(&self, cx: &mut AppContext); - fn update_matches(&self, matches: &Vec>, cx: &mut AppContext); - fn query_suggestion(&self, cx: &mut AppContext) -> String; - fn activate_match(&self, index: usize, matches: &Vec>, cx: &mut AppContext); + fn clear_matches(&self, cx: &mut WindowContext); + fn update_matches(&self, matches: &Vec>, cx: &mut WindowContext); + fn query_suggestion(&self, cx: &mut WindowContext) -> String; + fn activate_match( + &self, + index: usize, + matches: &Vec>, + cx: &mut WindowContext, + ); fn match_index_for_direction( &self, matches: &Vec>, current_index: usize, direction: Direction, - cx: &mut AppContext, + cx: &mut WindowContext, ) -> usize; fn find_matches( &self, query: SearchQuery, - cx: &mut AppContext, + cx: &mut WindowContext, ) -> Task>>; fn active_match_index( &self, matches: &Vec>, - cx: &mut AppContext, + cx: &mut WindowContext, ) -> Option; } @@ -131,8 +136,8 @@ impl SearchableItemHandle for ViewHandle { fn subscribe_to_search_events( &self, - cx: &mut AppContext, - handler: Box, + cx: &mut WindowContext, + handler: Box, ) -> Subscription { cx.subscribe(self, move |_, event, cx| { if let Some(search_event) = T::to_search_event(event) { @@ -141,21 +146,21 @@ impl SearchableItemHandle for ViewHandle { }) } - fn clear_matches(&self, cx: &mut AppContext) { + fn clear_matches(&self, cx: &mut WindowContext) { self.update(cx, |this, cx| this.clear_matches(cx)); } - fn update_matches(&self, matches: &Vec>, cx: &mut AppContext) { + fn update_matches(&self, matches: &Vec>, cx: &mut WindowContext) { let matches = downcast_matches(matches); self.update(cx, |this, cx| this.update_matches(matches, cx)); } - fn query_suggestion(&self, cx: &mut AppContext) -> String { + fn query_suggestion(&self, cx: &mut WindowContext) -> String { self.update(cx, |this, cx| this.query_suggestion(cx)) } fn activate_match( &self, index: usize, matches: &Vec>, - cx: &mut AppContext, + cx: &mut WindowContext, ) { let matches = downcast_matches(matches); self.update(cx, |this, cx| this.activate_match(index, matches, cx)); @@ -165,7 +170,7 @@ impl SearchableItemHandle for ViewHandle { matches: &Vec>, current_index: usize, direction: Direction, - cx: &mut AppContext, + cx: &mut WindowContext, ) -> usize { let matches = downcast_matches(matches); self.update(cx, |this, cx| { @@ -175,7 +180,7 @@ impl SearchableItemHandle for ViewHandle { fn find_matches( &self, query: SearchQuery, - cx: &mut AppContext, + cx: &mut WindowContext, ) -> Task>> { let matches = self.update(cx, |this, cx| this.find_matches(query, cx)); cx.foreground().spawn(async { @@ -189,7 +194,7 @@ impl SearchableItemHandle for ViewHandle { fn active_match_index( &self, matches: &Vec>, - cx: &mut AppContext, + cx: &mut WindowContext, ) -> Option { let matches = downcast_matches(matches); self.update(cx, |this, cx| this.active_match_index(matches, cx)) diff --git a/crates/workspace/src/toolbar.rs b/crates/workspace/src/toolbar.rs index 04130beeac..c47b2718ff 100644 --- a/crates/workspace/src/toolbar.rs +++ b/crates/workspace/src/toolbar.rs @@ -1,7 +1,7 @@ use crate::{ItemHandle, Pane}; use gpui::{ elements::*, platform::CursorStyle, platform::MouseButton, Action, AnyViewHandle, AppContext, - Element, Entity, View, ViewContext, ViewHandle, WeakViewHandle, + Element, Entity, View, ViewContext, ViewHandle, WeakViewHandle, WindowContext, }; use settings::Settings; @@ -21,7 +21,7 @@ pub trait ToolbarItemView: View { current_location } - fn pane_focus_update(&mut self, _pane_focused: bool, _cx: &mut AppContext) {} + fn pane_focus_update(&mut self, _pane_focused: bool, _cx: &mut ViewContext) {} } trait ToolbarItemViewHandle { @@ -30,9 +30,9 @@ trait ToolbarItemViewHandle { fn set_active_pane_item( &self, active_pane_item: Option<&dyn ItemHandle>, - cx: &mut AppContext, + cx: &mut WindowContext, ) -> ToolbarItemLocation; - fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut AppContext); + fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut WindowContext); } #[derive(Copy, Clone, Debug, PartialEq)] @@ -263,7 +263,7 @@ impl Toolbar { } } - pub fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut AppContext) { + pub fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut ViewContext) { for (toolbar_item, _) in self.items.iter_mut() { toolbar_item.pane_focus_update(pane_focused, cx); } @@ -292,14 +292,14 @@ impl ToolbarItemViewHandle for ViewHandle { fn set_active_pane_item( &self, active_pane_item: Option<&dyn ItemHandle>, - cx: &mut AppContext, + cx: &mut WindowContext, ) -> ToolbarItemLocation { self.update(cx, |this, cx| { this.set_active_pane_item(active_pane_item, cx) }) } - fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut AppContext) { + fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut WindowContext) { self.update(cx, |this, cx| this.pane_focus_update(pane_focused, cx)); } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index ded8b05a13..3cc9beb160 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -397,20 +397,18 @@ pub fn init(app_state: Arc, cx: &mut AppContext) { .await .context("Failed to create CLI symlink"); - cx.update(|cx| { - workspace.update(cx, |workspace, cx| { - if matches!(err, Err(_)) { - err.notify_err(workspace, cx); - } else { - workspace.show_notification(1, cx, |cx| { - cx.add_view(|_| { - MessageNotification::new_message( - "Successfully installed the `zed` binary", - ) - }) - }); - } - }) + workspace.update(&mut cx, |workspace, cx| { + if matches!(err, Err(_)) { + err.notify_err(workspace, cx); + } else { + workspace.show_notification(1, cx, |cx| { + cx.add_view(|_| { + MessageNotification::new_message( + "Successfully installed the `zed` binary", + ) + }) + }); + } }) }) .detach(); @@ -724,11 +722,9 @@ impl Workspace { Stream::map(current_user, drop).merge(Stream::map(connection_status, drop)); while stream.recv().await.is_some() { - cx.update(|cx| { - if let Some(this) = this.upgrade(cx) { - this.update(cx, |_, cx| cx.notify()); - } - }) + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |_, cx| cx.notify()); + } } }); let handle = cx.handle(); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index e8f394df82..1823db9ae2 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -1012,12 +1012,11 @@ mod tests { let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); // Open a file within an existing worktree. - cx.update(|cx| { - workspace.update(cx, |view, cx| { + workspace + .update(cx, |view, cx| { view.open_paths(vec!["/dir1/a.txt".into()], true, cx) }) - }) - .await; + .await; cx.read(|cx| { assert_eq!( workspace @@ -1036,12 +1035,11 @@ mod tests { }); // Open a file outside of any existing worktree. - cx.update(|cx| { - workspace.update(cx, |view, cx| { + workspace + .update(cx, |view, cx| { view.open_paths(vec!["/dir2/b.txt".into()], true, cx) }) - }) - .await; + .await; cx.read(|cx| { let worktree_roots = workspace .read(cx) @@ -1072,12 +1070,11 @@ mod tests { }); // Ensure opening a directory and one of its children only adds one worktree. - cx.update(|cx| { - workspace.update(cx, |view, cx| { + workspace + .update(cx, |view, cx| { view.open_paths(vec!["/dir3".into(), "/dir3/c.txt".into()], true, cx) }) - }) - .await; + .await; cx.read(|cx| { let worktree_roots = workspace .read(cx) @@ -1108,12 +1105,11 @@ mod tests { }); // Ensure opening invisibly a file outside an existing worktree adds a new, invisible worktree. - cx.update(|cx| { - workspace.update(cx, |view, cx| { + workspace + .update(cx, |view, cx| { view.open_paths(vec!["/d.txt".into()], false, cx) }) - }) - .await; + .await; cx.read(|cx| { let worktree_roots = workspace .read(cx) @@ -1171,19 +1167,18 @@ mod tests { let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); // Open a file within an existing worktree. - cx.update(|cx| { - workspace.update(cx, |view, cx| { + workspace + .update(cx, |view, cx| { view.open_paths(vec![PathBuf::from("/root/a.txt")], true, cx) }) - }) - .await; + .await; let editor = cx.read(|cx| { let pane = workspace.read(cx).active_pane().read(cx); let item = pane.active_item().unwrap(); item.downcast::().unwrap() }); - cx.update(|cx| editor.update(cx, |editor, cx| editor.handle_input("x", cx))); + editor.update(cx, |editor, cx| editor.handle_input("x", cx)); app_state .fs .as_fake()