@@ -12,7 +12,7 @@ use gpui::{
View, ViewContext, ViewHandle, WeakViewHandle,
};
use project::{Project, ProjectEntryId, ProjectPath};
-use std::{any::Any, cell::RefCell, cmp, mem, rc::Rc};
+use std::{any::Any, cell::RefCell, cmp, mem, path::Path, rc::Rc};
use util::ResultExt;
action!(Split, SplitDirection);
@@ -443,14 +443,14 @@ impl Pane {
}) {
let item =
this.read_with(&cx, |this, _| this.items[item_to_close_ix].boxed_clone());
- if cx.read(|cx| item.can_save(cx)) {
- if cx.read(|cx| item.has_conflict(cx)) {
+ if cx.read(|cx| item.is_dirty(cx)) {
+ if cx.read(|cx| item.can_save(cx)) {
let mut answer = this.update(&mut cx, |this, cx| {
this.activate_item(item_to_close_ix, true, cx);
cx.prompt(
PromptLevel::Warning,
- CONFLICT_MESSAGE,
- &["Overwrite", "Discard", "Cancel"],
+ DIRTY_MESSAGE,
+ &["Save", "Don't Save", "Cancel"],
)
});
@@ -465,19 +465,10 @@ impl Pane {
break;
}
}
- Some(1) => {
- if cx
- .update(|cx| item.reload(project.clone(), cx))
- .await
- .log_err()
- .is_none()
- {
- break;
- }
- }
+ Some(1) => {}
_ => break,
}
- } else if cx.read(|cx| item.is_dirty(cx)) {
+ } else if cx.read(|cx| item.can_save_as(cx)) {
let mut answer = this.update(&mut cx, |this, cx| {
this.activate_item(item_to_close_ix, true, cx);
cx.prompt(
@@ -489,12 +480,25 @@ impl Pane {
match answer.next().await {
Some(0) => {
- if cx
- .update(|cx| item.save(project.clone(), cx))
- .await
- .log_err()
- .is_none()
- {
+ let start_abs_path = project
+ .read_with(&cx, |project, cx| {
+ let worktree = project.visible_worktrees(cx).next()?;
+ Some(worktree.read(cx).as_local()?.abs_path().to_path_buf())
+ })
+ .unwrap_or(Path::new("").into());
+
+ let mut abs_path =
+ cx.update(|cx| cx.prompt_for_new_path(&start_abs_path));
+ if let Some(abs_path) = abs_path.next().await.flatten() {
+ if cx
+ .update(|cx| item.save_as(project.clone(), abs_path, cx))
+ .await
+ .log_err()
+ .is_none()
+ {
+ break;
+ }
+ } else {
break;
}
}
@@ -502,6 +506,39 @@ impl Pane {
_ => break,
}
}
+ } else if cx.read(|cx| item.has_conflict(cx) && item.can_save(cx)) {
+ let mut answer = this.update(&mut cx, |this, cx| {
+ this.activate_item(item_to_close_ix, true, cx);
+ cx.prompt(
+ PromptLevel::Warning,
+ CONFLICT_MESSAGE,
+ &["Overwrite", "Discard", "Cancel"],
+ )
+ });
+
+ match answer.next().await {
+ Some(0) => {
+ if cx
+ .update(|cx| item.save(project.clone(), cx))
+ .await
+ .log_err()
+ .is_none()
+ {
+ break;
+ }
+ }
+ Some(1) => {
+ if cx
+ .update(|cx| item.reload(project.clone(), cx))
+ .await
+ .log_err()
+ .is_none()
+ {
+ break;
+ }
+ }
+ _ => break,
+ }
}
this.update(&mut cx, |this, cx| {
@@ -532,6 +569,7 @@ impl Pane {
} else {
this.focus_active_item(cx);
this.activate(cx);
+ cx.emit(Event::ActivateItem { local: true });
}
this.update_toolbar(cx);
cx.notify();
@@ -832,32 +870,58 @@ mod tests {
let params = cx.update(WorkspaceParams::test);
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- let item1 = cx.add_view(window_id, |_| TestItem::new(false, true));
- let item2 = cx.add_view(window_id, |_| TestItem::new(true, true));
- let item3 = cx.add_view(window_id, |_| TestItem::new(false, true));
- let item4 = cx.add_view(window_id, |_| TestItem::new(true, false));
+ let item1 = cx.add_view(window_id, |_| {
+ let mut item = TestItem::new();
+ item.has_conflict = true;
+ item
+ });
+ let item2 = cx.add_view(window_id, |_| {
+ let mut item = TestItem::new();
+ item.is_dirty = true;
+ item.has_conflict = true;
+ item
+ });
+ let item3 = cx.add_view(window_id, |_| {
+ let mut item = TestItem::new();
+ item.has_conflict = true;
+ item
+ });
+ let item4 = cx.add_view(window_id, |_| {
+ let mut item = TestItem::new();
+ item.is_dirty = true;
+ item
+ });
+ let item5 = cx.add_view(window_id, |_| {
+ let mut item = TestItem::new();
+ item.is_dirty = true;
+ item.can_save = false;
+ item
+ });
let pane = workspace.update(cx, |workspace, cx| {
workspace.add_item(Box::new(item1.clone()), cx);
+ workspace.add_item(Box::new(item2.clone()), cx);
workspace.add_item(Box::new(item3.clone()), cx);
workspace.add_item(Box::new(item4.clone()), cx);
- workspace.add_item(Box::new(item2.clone()), cx);
- assert_eq!(workspace.active_item(cx).unwrap().id(), item2.id());
-
+ workspace.add_item(Box::new(item5.clone()), cx);
workspace.active_pane().clone()
});
let close_items = pane.update(cx, |pane, cx| {
+ pane.activate_item(1, true, cx);
+ assert_eq!(pane.active_item().unwrap().id(), item2.id());
+
let item1_id = item1.id();
let item3_id = item3.id();
let item4_id = item4.id();
+ let item5_id = item5.id();
pane.close_items(cx, move |id| {
- id == item1_id || id == item3_id || id == item4_id
+ [item1_id, item3_id, item4_id, item5_id].contains(&id)
})
});
cx.foreground().run_until_parked();
pane.read_with(cx, |pane, _| {
- assert_eq!(pane.items.len(), 4);
+ assert_eq!(pane.items.len(), 5);
assert_eq!(pane.active_item().unwrap().id(), item1.id());
});
@@ -865,8 +929,9 @@ mod tests {
cx.foreground().run_until_parked();
pane.read_with(cx, |pane, cx| {
assert_eq!(item1.read(cx).save_count, 1);
+ assert_eq!(item1.read(cx).save_as_count, 0);
assert_eq!(item1.read(cx).reload_count, 0);
- assert_eq!(pane.items.len(), 3);
+ assert_eq!(pane.items.len(), 4);
assert_eq!(pane.active_item().unwrap().id(), item3.id());
});
@@ -874,35 +939,53 @@ mod tests {
cx.foreground().run_until_parked();
pane.read_with(cx, |pane, cx| {
assert_eq!(item3.read(cx).save_count, 0);
+ assert_eq!(item3.read(cx).save_as_count, 0);
assert_eq!(item3.read(cx).reload_count, 1);
- assert_eq!(pane.items.len(), 2);
+ assert_eq!(pane.items.len(), 3);
assert_eq!(pane.active_item().unwrap().id(), item4.id());
});
cx.simulate_prompt_answer(window_id, 0);
- close_items.await;
+ cx.foreground().run_until_parked();
pane.read_with(cx, |pane, cx| {
assert_eq!(item4.read(cx).save_count, 1);
+ assert_eq!(item4.read(cx).save_as_count, 0);
assert_eq!(item4.read(cx).reload_count, 0);
+ assert_eq!(pane.items.len(), 2);
+ assert_eq!(pane.active_item().unwrap().id(), item5.id());
+ });
+
+ cx.simulate_prompt_answer(window_id, 0);
+ cx.foreground().run_until_parked();
+ cx.simulate_new_path_selection(|_| Some(Default::default()));
+ close_items.await;
+ pane.read_with(cx, |pane, cx| {
+ assert_eq!(item5.read(cx).save_count, 0);
+ assert_eq!(item5.read(cx).save_as_count, 1);
+ assert_eq!(item5.read(cx).reload_count, 0);
assert_eq!(pane.items.len(), 1);
assert_eq!(pane.active_item().unwrap().id(), item2.id());
});
}
struct TestItem {
- is_dirty: bool,
- has_conflict: bool,
save_count: usize,
+ save_as_count: usize,
reload_count: usize,
+ is_dirty: bool,
+ has_conflict: bool,
+ can_save: bool,
}
impl TestItem {
- fn new(is_dirty: bool, has_conflict: bool) -> Self {
+ fn new() -> Self {
Self {
save_count: 0,
+ save_as_count: 0,
reload_count: 0,
- is_dirty,
- has_conflict,
+ is_dirty: false,
+ has_conflict: false,
+ can_save: true,
}
}
}
@@ -945,7 +1028,7 @@ mod tests {
}
fn can_save(&self, _: &AppContext) -> bool {
- true
+ self.can_save
}
fn save(
@@ -958,7 +1041,7 @@ mod tests {
}
fn can_save_as(&self, _: &AppContext) -> bool {
- false
+ true
}
fn save_as(
@@ -967,7 +1050,8 @@ mod tests {
_: std::path::PathBuf,
_: &mut ViewContext<Self>,
) -> Task<anyhow::Result<()>> {
- unreachable!()
+ self.save_as_count += 1;
+ Task::ready(Ok(()))
}
fn reload(