fix: buffer-close ensuring writes

Make sure buffer-close waits for the document to finish its writes.
pull/2267/head
Skyler Hawthorne 2 years ago
parent d706194597
commit a5a93182cd

@ -310,6 +310,8 @@ impl Application {
self.render(); self.render();
} }
event = self.editor.wait_event() => { event = self.editor.wait_event() => {
log::debug!("received editor event: {:?}", event);
match event { match event {
EditorEvent::DocumentSave(event) => { EditorEvent::DocumentSave(event) => {
self.handle_document_write(event); self.handle_document_write(event);

@ -151,6 +151,7 @@ fn buffer_close(
} }
let document_ids = buffer_gather_paths_impl(cx.editor, args); let document_ids = buffer_gather_paths_impl(cx.editor, args);
log::debug!("closing buffers: {:?}", document_ids);
buffer_close_by_ids_impl(cx.editor, &document_ids, false) buffer_close_by_ids_impl(cx.editor, &document_ids, false)
} }

@ -26,7 +26,6 @@ async fn test_write_quit_fail() -> anyhow::Result<()> {
} }
#[tokio::test] #[tokio::test]
#[ignore]
async fn test_buffer_close_concurrent() -> anyhow::Result<()> { async fn test_buffer_close_concurrent() -> anyhow::Result<()> {
test_key_sequences( test_key_sequences(
&mut Application::new(Args::default(), Config::default())?, &mut Application::new(Args::default(), Config::default())?,

@ -616,6 +616,10 @@ impl Document {
} }
pub async fn await_save(&mut self) -> Option<DocumentSaveEventResult> { pub async fn await_save(&mut self) -> Option<DocumentSaveEventResult> {
self.await_save_impl(true).await
}
async fn await_save_impl(&mut self, block: bool) -> Option<DocumentSaveEventResult> {
let mut current_save = self.current_save.lock().await; let mut current_save = self.current_save.lock().await;
if let Some(ref mut save) = *current_save { if let Some(ref mut save) = *current_save {
let result = save.await; let result = save.await;
@ -627,7 +631,15 @@ impl Document {
// return early if the receiver is closed // return early if the receiver is closed
self.save_receiver.as_ref()?; self.save_receiver.as_ref()?;
let save = match self.save_receiver.as_mut().unwrap().recv().await { let rx = self.save_receiver.as_mut().unwrap();
let save_req = if block {
rx.recv().await
} else {
rx.try_recv().ok()
};
let save = match save_req {
Some(save) => save, Some(save) => save,
None => { None => {
self.save_receiver = None; self.save_receiver = None;
@ -648,19 +660,24 @@ impl Document {
Some(result) Some(result)
} }
/// Prepares the Document for being closed by stopping any new writes /// Flushes the queue of pending writes. If any fail,
/// and flushing through the queue of pending writes. If any fail, /// it stops early before emptying the rest of the queue.
/// it stops early before emptying the rest of the queue. Callers pub async fn try_flush_saves(&mut self) -> Option<DocumentSaveEventResult> {
/// should keep calling until it returns None. self.flush_saves_impl(false).await
pub async fn close(&mut self) -> Option<DocumentSaveEventResult> { }
if self.save_sender.is_some() {
self.save_sender = None;
}
async fn flush_saves_impl(&mut self, block: bool) -> Option<DocumentSaveEventResult> {
let mut final_result = None; let mut final_result = None;
while let Some(save_event) = self.await_save().await { while let Some(save_event) = self.await_save_impl(block).await {
let is_err = save_event.is_err(); let is_err = match &save_event {
Ok(event) => {
self.set_last_saved_revision(event.revision);
false
}
Err(_) => true,
};
final_result = Some(save_event); final_result = Some(save_event);
if is_err { if is_err {
@ -671,6 +688,17 @@ impl Document {
final_result final_result
} }
/// Prepares the Document for being closed by stopping any new writes
/// and flushing through the queue of pending writes. If any fail,
/// it stops early before emptying the rest of the queue.
pub async fn close(&mut self) -> Option<DocumentSaveEventResult> {
if self.save_sender.is_some() {
self.save_sender = None;
}
self.flush_saves_impl(true).await
}
/// Detect the programming language based on the file type. /// Detect the programming language based on the file type.
pub fn detect_language(&mut self, config_loader: Arc<syntax::Loader>) { pub fn detect_language(&mut self, config_loader: Arc<syntax::Loader>) {
if let Some(path) = &self.path { if let Some(path) = &self.path {
@ -1023,6 +1051,11 @@ impl Document {
let history = self.history.take(); let history = self.history.take();
let current_revision = history.current_revision(); let current_revision = history.current_revision();
self.history.set(history); self.history.set(history);
log::debug!(
"modified - last saved: {}, current: {}",
self.last_saved_revision,
current_revision
);
current_revision != self.last_saved_revision || !self.changes.is_empty() current_revision != self.last_saved_revision || !self.changes.is_empty()
} }
@ -1036,9 +1069,20 @@ impl Document {
/// Set the document's latest saved revision to the given one. /// Set the document's latest saved revision to the given one.
pub fn set_last_saved_revision(&mut self, rev: usize) { pub fn set_last_saved_revision(&mut self, rev: usize) {
log::debug!(
"doc {} revision updated {} -> {}",
self.id,
self.last_saved_revision,
rev
);
self.last_saved_revision = rev; self.last_saved_revision = rev;
} }
/// Get the document's latest saved revision.
pub fn get_last_saved_revision(&mut self) -> usize {
self.last_saved_revision
}
/// Get the current revision number /// Get the current revision number
pub fn get_current_revision(&mut self) -> usize { pub fn get_current_revision(&mut self) -> usize {
let history = self.history.take(); let history = self.history.take();

@ -1101,6 +1101,11 @@ impl Editor {
None => return Err(CloseError::DoesNotExist), None => return Err(CloseError::DoesNotExist),
}; };
// flush out any pending writes first to clear the modified status
if let Some(save_result) = doc.try_flush_saves().await {
save_result?;
}
if !force && doc.is_modified() { if !force && doc.is_modified() {
return Err(CloseError::BufferModified(doc.display_name().into_owned())); return Err(CloseError::BufferModified(doc.display_name().into_owned()));
} }

Loading…
Cancel
Save