JSON based migrations (#39398)

Closes #ISSUE

Adds the ability to create settings and keymap migrations by mutating
`serde_json::Value`s instead of using tree-sitter queries. This
(hopefully) will make complicated migrations far simpler to implement.

Release Notes:

- N/A *or* Added/Fixed/Improved ...

---------

Co-authored-by: Smit <heysmitbarmase@gmail.com>
Co-authored-by: Smit <smit@zed.dev>
This commit is contained in:
Ben Kunkle
2025-10-02 16:07:26 -04:00
committed by GitHub
co-authored by Smit Smit
parent af630be7ca
commit 7c3a21f732
5 changed files with 112 additions and 54 deletions
+43 -20
View File
@@ -1231,32 +1231,55 @@ pub fn handle_settings_file_changes(
MigrationNotification::set_global(cx.new(|_| MigrationNotification), cx);
// Helper function to process settings content
let process_settings =
move |content: String, is_user: bool, store: &mut SettingsStore, cx: &mut App| -> bool {
// Apply migrations to both user and global settings
let (processed_content, content_migrated) =
if let Ok(Some(migrated_content)) = migrate_settings(&content) {
let process_settings = move |content: String,
is_user: bool,
store: &mut SettingsStore,
cx: &mut App|
-> bool {
let id = NotificationId::Named("failed-to-migrate-settings".into());
// Apply migrations to both user and global settings
let (processed_content, content_migrated) = match migrate_settings(&content) {
Ok(result) => {
dismiss_app_notification(&id, cx);
if let Some(migrated_content) = result {
(migrated_content, true)
} else {
(content, false)
};
let result = if is_user {
store.set_user_settings(&processed_content, cx)
} else {
store.set_global_settings(&processed_content, cx)
};
if let Err(err) = &result {
let settings_type = if is_user { "user" } else { "global" };
log::error!("Failed to load {} settings: {err}", settings_type);
}
}
Err(err) => {
show_app_notification(id, cx, move |cx| {
cx.new(|cx| {
MessageNotification::new(format!("Failed to migrate settings\n{err}"), cx)
.primary_message("Open Settings File")
.primary_icon(IconName::Settings)
.primary_on_click(|window, cx| {
window.dispatch_action(zed_actions::OpenSettings.boxed_clone(), cx);
cx.emit(DismissEvent);
})
})
});
// notify user here
(content, false)
}
settings_changed(result.err(), cx);
content_migrated
};
let result = if is_user {
store.set_user_settings(&processed_content, cx)
} else {
store.set_global_settings(&processed_content, cx)
};
if let Err(err) = &result {
let settings_type = if is_user { "user" } else { "global" };
log::error!("Failed to load {} settings: {err}", settings_type);
}
settings_changed(result.err(), cx);
content_migrated
};
// Initial load of both settings files
let global_content = cx
.background_executor()