Do not serialize buffers containing bundled files (#38102)

Fix bundled file persistence by introducing SerializationMode enum

Closes: #38094

What's the issue?

Opening bundled files like Default Key Bindings
(zed://settings/keymap-default.json) was causing SQLite foreign key
constraint errors. The editor was trying to save state for these
read-only assets just like regular files, but since bundled files don't
have database entries, the foreign key constraint would fail.

The fix

Replaced the boolean serialize_dirty_buffers flag with a type-safe
SerializationMode enum:

```rust
pub enum SerializationMode {
    Enabled,   // Regular files persist across sessions
    Disabled,  // Bundled files don't persist
}
```

This prevents serialization at the source: workspace_id() returns None
for disabled editors, serialize() bails early, and should_serialize()
returns false. When opening bundled files, we set the mode to Disabled
from the start, so they're treated as transient views that never
interact with the persistence layer.

Changes

- editor.rs: Added SerializationMode enum and updated serialization
methods to respect it
- items.rs: Guarded should_serialize() to prevent disabled editors from
being serialized
- zed.rs: Set SerializationMode::Disabled in open_bundled_file()

Result

Bundled files open cleanly without SQLite errors and don't persist
across workspace reloads (expected behavior). Regular file persistence
remains unaffected.

Release Notes: Fixed SQLite foreign key constraint errors when opening
bundled files like Default Key Bindings.

---------

Co-authored-by: MrSubidubi <finn@zed.dev>
This commit is contained in:
ʟᴜɴᴇx
2025-11-06 13:30:03 +00:00
committed by GitHub
co-authored by MrSubidubi
parent a7163623e7
commit 7a37dd9433
3 changed files with 66 additions and 25 deletions
+14 -15
View File
@@ -1,7 +1,7 @@
use crate::{
Anchor, Autoscroll, Editor, EditorEvent, EditorSettings, ExcerptId, ExcerptRange, FormatTarget,
MultiBuffer, MultiBufferSnapshot, NavigationData, ReportEditorEvent, SearchWithinRange,
SelectionEffects, ToPoint as _,
Anchor, Autoscroll, BufferSerialization, Editor, EditorEvent, EditorSettings, ExcerptId,
ExcerptRange, FormatTarget, MultiBuffer, MultiBufferSnapshot, NavigationData,
ReportEditorEvent, SearchWithinRange, SelectionEffects, ToPoint as _,
display_map::HighlightKey,
editor_settings::SeedQuerySetting,
persistence::{DB, SerializedEditor},
@@ -1256,17 +1256,15 @@ impl SerializableItem for Editor {
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Task<Result<()>>> {
if self.mode.is_minimap() {
return None;
}
let mut serialize_dirty_buffers = self.serialize_dirty_buffers;
let buffer_serialization = self.buffer_serialization?;
let project = self.project.clone()?;
if project.read(cx).visible_worktrees(cx).next().is_none() {
let serialize_dirty_buffers = match buffer_serialization {
// If we don't have a worktree, we don't serialize, because
// projects without worktrees aren't deserialized.
serialize_dirty_buffers = false;
}
BufferSerialization::All => project.read(cx).visible_worktrees(cx).next().is_some(),
BufferSerialization::NonDirtyBuffers => false,
};
if closing && !serialize_dirty_buffers {
return None;
@@ -1323,10 +1321,11 @@ impl SerializableItem for Editor {
}
fn should_serialize(&self, event: &Self::Event) -> bool {
matches!(
event,
EditorEvent::Saved | EditorEvent::DirtyChanged | EditorEvent::BufferEdited
)
self.should_serialize_buffer()
&& matches!(
event,
EditorEvent::Saved | EditorEvent::DirtyChanged | EditorEvent::BufferEdited
)
}
}