Detailed changes
@@ -343,6 +343,23 @@ impl TestAppContext {
pub fn did_prompt_for_new_path(&self) -> bool {
self.1.as_ref().did_prompt_for_new_path()
}
+
+ pub fn simulate_prompt_answer(&self, window_id: usize, answer: usize) {
+ let mut state = self.0.borrow_mut();
+ let (_, window) = state
+ .presenters_and_platform_windows
+ .get_mut(&window_id)
+ .unwrap();
+ let test_window = window
+ .as_any_mut()
+ .downcast_mut::<platform::test::Window>()
+ .unwrap();
+ let callback = test_window
+ .last_prompt
+ .take()
+ .expect("prompt was not called");
+ (callback)(answer);
+ }
}
impl UpdateModel for TestAppContext {
@@ -27,6 +27,7 @@ use objc::{
use pathfinder_geometry::vector::vec2f;
use smol::Timer;
use std::{
+ any::Any,
cell::{Cell, RefCell},
convert::TryInto,
ffi::c_void,
@@ -263,6 +264,10 @@ impl Drop for Window {
}
impl platform::Window for Window {
+ fn as_any_mut(&mut self) -> &mut dyn Any {
+ self
+ }
+
fn on_event(&mut self, callback: Box<dyn FnMut(Event)>) {
self.0.as_ref().borrow_mut().event_callback = Some(callback);
}
@@ -68,6 +68,7 @@ pub trait Dispatcher: Send + Sync {
}
pub trait Window: WindowContext {
+ fn as_any_mut(&mut self) -> &mut dyn Any;
fn on_event(&mut self, callback: Box<dyn FnMut(Event)>);
fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn WindowContext)>);
fn on_close(&mut self, callback: Box<dyn FnOnce()>);
@@ -24,6 +24,7 @@ pub struct Window {
event_handlers: Vec<Box<dyn FnMut(super::Event)>>,
resize_handlers: Vec<Box<dyn FnMut(&mut dyn super::WindowContext)>>,
close_handlers: Vec<Box<dyn FnOnce()>>,
+ pub(crate) last_prompt: RefCell<Option<Box<dyn FnOnce(usize)>>>,
}
impl Platform {
@@ -123,6 +124,7 @@ impl Window {
close_handlers: Vec::new(),
scale_factor: 1.0,
current_scene: None,
+ last_prompt: RefCell::new(None),
}
}
}
@@ -152,6 +154,10 @@ impl super::WindowContext for Window {
}
impl super::Window for Window {
+ fn as_any_mut(&mut self) -> &mut dyn Any {
+ self
+ }
+
fn on_event(&mut self, callback: Box<dyn FnMut(crate::Event)>) {
self.event_handlers.push(callback);
}
@@ -164,7 +170,9 @@ impl super::Window for Window {
self.close_handlers.push(callback);
}
- fn prompt(&self, _: crate::PromptLevel, _: &str, _: &[&str], _: Box<dyn FnOnce(usize)>) {}
+ fn prompt(&self, _: crate::PromptLevel, _: &str, _: &[&str], f: Box<dyn FnOnce(usize)>) {
+ self.last_prompt.replace(Some(f));
+ }
}
pub(crate) fn platform() -> Platform {
@@ -761,7 +761,7 @@ mod tests {
use crate::{editor::BufferView, settings, test::temp_tree};
use gpui::App;
use serde_json::json;
- use std::collections::HashSet;
+ use std::{collections::HashSet, fs};
use tempdir::TempDir;
#[test]
@@ -1101,6 +1101,59 @@ mod tests {
});
}
+ #[test]
+ fn test_save_conflicting_item() {
+ App::test_async((), |mut app| async move {
+ let dir = temp_tree(json!({
+ "a.txt": "",
+ }));
+
+ let settings = settings::channel(&app.font_cache()).unwrap().1;
+ let (window_id, workspace) = app.add_window(|ctx| {
+ let mut workspace = Workspace::new(0, settings, ctx);
+ workspace.add_worktree(dir.path(), ctx);
+ workspace
+ });
+ let tree = app.read(|ctx| {
+ let mut trees = workspace.read(ctx).worktrees().iter();
+ trees.next().unwrap().clone()
+ });
+ tree.flush_fs_events(&app).await;
+
+ // Open a file within an existing worktree.
+ app.update(|ctx| {
+ workspace.update(ctx, |view, ctx| {
+ view.open_paths(&[dir.path().join("a.txt")], ctx)
+ })
+ })
+ .await;
+ let editor = app.read(|ctx| {
+ let pane = workspace.read(ctx).active_pane().read(ctx);
+ let item = pane.active_item().unwrap();
+ item.to_any().downcast::<BufferView>().unwrap()
+ });
+
+ app.update(|ctx| {
+ editor.update(ctx, |editor, ctx| editor.insert(&"x".to_string(), ctx))
+ });
+ fs::write(dir.path().join("a.txt"), "changed").unwrap();
+ tree.flush_fs_events(&app).await;
+ app.read(|ctx| {
+ assert!(editor.is_dirty(ctx));
+ assert!(editor.has_conflict(ctx));
+ });
+
+ app.update(|ctx| workspace.update(ctx, |w, ctx| w.save_active_item(&(), ctx)));
+ app.simulate_prompt_answer(window_id, 0);
+ tree.update(&mut app, |tree, ctx| tree.next_scan_complete(ctx))
+ .await;
+ app.read(|ctx| {
+ assert!(!editor.is_dirty(ctx));
+ assert!(!editor.has_conflict(ctx));
+ });
+ });
+ }
+
#[test]
fn test_pane_actions() {
App::test_async((), |mut app| async move {