Files
ElyOffice/apps/ely-mark/src/autosave.rs
T
ZacharyZhang-NYandClaude Opus 5.5 1f2920020a ElyMark: the file in MarkdownDocument, no web page
The view holds the component library's MarkdownDocument: the file's text
is the document's text, saved as read when unedited. Find, tables,
attachments, the look and export, which ran in the page, go until their
own tasks rebuild them natively. The window scripts that drove the page
go with it; gpui window tests cover the view.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 02:37:53 -04:00

70 lines
2.3 KiB
Rust

//! ElyMark saves a second after typing stops (§6.2).
use std::time::{Duration, Instant};
use ely_files::{Action, DEBOUNCE, SaveState};
use ely_office::{in_window, prelude::*};
use gpui::{Context, Window};
use crate::desk::Desk;
use crate::outside::Outside;
impl Desk {
/// A text change restarts the wait; finished saves report.
pub fn autosave(&mut self, id: u64, changed: u64, cx: &mut Context<Self>) {
let Some(tab) = self.tab_mut(id) else {
return;
};
let saving = tab.exporting || tab.session.state() == SaveState::Saving;
if let Some(revision) = tab.extra.writing.filter(|_| !saving) {
let ok = tab.session.state() != SaveState::SaveFailed;
tab.extra.policy.save_finished(revision, ok);
tab.extra.writing = None;
}
if tab.session.path().is_some() {
tab.extra.policy.set_has_path();
}
// Any count other than the last heard is news.
if changed == tab.extra.heard {
return;
}
tab.extra.heard = changed;
self.save_after_pause(id, cx);
}
/// Counts unsaved text as an edit; saves after the pause.
pub fn save_after_pause(&mut self, id: u64, cx: &mut Context<Self>) {
let Some(tab) = self.tab_mut(id) else {
return;
};
tab.extra.policy.edit(Instant::now());
cx.spawn(async move |desk, cx| {
let wait = DEBOUNCE + Duration::from_millis(50);
cx.background_executor().timer(wait).await;
in_window(&desk, cx, |desk, window, cx| {
desk.autosave_due(id, window, cx)
})
.ok();
})
.detach();
}
fn autosave_due(&mut self, id: u64, window: &mut Window, cx: &mut Context<Self>) {
let Some(tab) = self.tab_mut(id) else {
return;
};
if !matches!(tab.extra.outside, Outside::Clear) || tab.extra.writing.is_some() {
return;
}
let Action::SaveDue(revision) = tab.extra.policy.tick(Instant::now()) else {
return;
};
if !tab.dirty(cx) {
return tab.extra.policy.save_finished(revision, true);
}
log::info!("mark: autosaves tab {id}");
tab.extra.writing = Some(revision);
self.save(id, None, window, cx);
}
}