Integrate document-format storage into the editor (#4265)

* Integrate document-format storage into the editor

* Address review feedback: drop redundant clones and dedupe metadata traversal

* Extract DocumentHistory and move storage-metadata tests to their own file

* Extract storage diffing/IO, gate validation and .gdd save behind preferences, restructure tests

* Address PR review: save-format/path consistency, autosave persistence, and view-settings/diff fixes

* Skip storage remount on .gdd open and split value/timestamp drift in attribute diff

* Rename storage tests module and surface .gdd open failures with per-resource diff detail

* Add debug-menu toggle to hide the storage preferences section

* Hopefully fix async tests

* Shorten comments

* Fix tests

* Review

* Review

* Review

* Block on future mesages in tests

* Review

* Shorten comments

---------

Co-authored-by: Timon <me@timon.zip>
This commit is contained in:
Dennis Kobert
2026-07-04 19:27:00 +00:00
committed by GitHub
co-authored by Timon
parent 294952e152
commit 540a4ff273
32 changed files with 2979 additions and 72 deletions
@@ -73,8 +73,10 @@ pub struct FutureMessageContext {}
#[derive(ExtractField)]
pub struct FutureMessageHandler {
#[cfg_attr(test, expect(dead_code))]
spawner: Arc<dyn MessageSpawner>,
wake: Wake,
#[cfg_attr(test, expect(dead_code))]
results_sender: UnboundedSender<Message>,
results_receiver: UnboundedReceiver<Message>,
}
@@ -119,7 +121,15 @@ impl MessageHandler<FutureMessage, FutureMessageContext> for FutureMessageHandle
fn process_message(&mut self, message: FutureMessage, _responses: &mut VecDeque<Message>, _context: FutureMessageContext) {
match message {
FutureMessage::Await { future } => {
#[cfg(not(test))]
self.spawner.spawn(future.into_future(), self.results_sender.clone(), self.wake.clone());
// For tests, block on the future to ensure the result is available when validating editor state afterwards.
#[cfg(test)]
{
let message = futures::executor::block_on(future.into_future());
_responses.push_back(message);
}
}
FutureMessage::Wake => {
// Tick-only message: the dispatcher's top-of-tick drain handles the real work.