diff --git a/crates/paths/src/paths.rs b/crates/paths/src/paths.rs index acb541acea..fa6217ce69 100644 --- a/crates/paths/src/paths.rs +++ b/crates/paths/src/paths.rs @@ -145,12 +145,24 @@ pub fn settings_file() -> &'static PathBuf { SETTINGS_FILE.get_or_init(|| config_dir().join("settings.json")) } +/// Returns the path to the `settings_backup.json` file. +pub fn settings_backup_file() -> &'static PathBuf { + static SETTINGS_FILE: OnceLock = OnceLock::new(); + SETTINGS_FILE.get_or_init(|| config_dir().join("settings_backup.json")) +} + /// Returns the path to the `keymap.json` file. pub fn keymap_file() -> &'static PathBuf { static KEYMAP_FILE: OnceLock = OnceLock::new(); KEYMAP_FILE.get_or_init(|| config_dir().join("keymap.json")) } +/// Returns the path to the `keymap_backup.json` file. +pub fn keymap_backup_file() -> &'static PathBuf { + static KEYMAP_FILE: OnceLock = OnceLock::new(); + KEYMAP_FILE.get_or_init(|| config_dir().join("keymap_backup.json")) +} + /// Returns the path to the `tasks.json` file. pub fn tasks_file() -> &'static PathBuf { static TASKS_FILE: OnceLock = OnceLock::new(); diff --git a/crates/settings/src/keymap_file.rs b/crates/settings/src/keymap_file.rs index 58c7915b91..fb967bde3f 100644 --- a/crates/settings/src/keymap_file.rs +++ b/crates/settings/src/keymap_file.rs @@ -588,24 +588,24 @@ impl KeymapFile { let Some(new_text) = migrate_keymap(&old_text) else { return Ok(()); }; - let initial_path = paths::keymap_file().as_path(); - if fs.is_file(initial_path).await { - let backup_path = paths::home_dir().join(".zed_keymap_backup"); - fs.atomic_write(backup_path, old_text) + let keymap_path = paths::keymap_file().as_path(); + if fs.is_file(keymap_path).await { + fs.atomic_write(paths::keymap_backup_file().to_path_buf(), old_text) .await .with_context(|| { "Failed to create settings backup in home directory".to_string() })?; - let resolved_path = fs.canonicalize(initial_path).await.with_context(|| { - format!("Failed to canonicalize keymap path {:?}", initial_path) - })?; + let resolved_path = fs + .canonicalize(keymap_path) + .await + .with_context(|| format!("Failed to canonicalize keymap path {:?}", keymap_path))?; fs.atomic_write(resolved_path.clone(), new_text) .await .with_context(|| format!("Failed to write keymap to file {:?}", resolved_path))?; } else { - fs.atomic_write(initial_path.to_path_buf(), new_text) + fs.atomic_write(keymap_path.to_path_buf(), new_text) .await - .with_context(|| format!("Failed to write keymap to file {:?}", initial_path))?; + .with_context(|| format!("Failed to write keymap to file {:?}", keymap_path))?; } Ok(()) diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index 2337f7fef3..6f69909b93 100644 --- a/crates/settings/src/settings_store.rs +++ b/crates/settings/src/settings_store.rs @@ -415,11 +415,11 @@ impl SettingsStore { let new_text = cx.read_global(|store: &SettingsStore, cx| { store.new_text_for_update::(old_text, |content| update(content, cx)) })?; - let initial_path = paths::settings_file().as_path(); - if fs.is_file(initial_path).await { + let settings_path = paths::settings_file().as_path(); + if fs.is_file(settings_path).await { let resolved_path = - fs.canonicalize(initial_path).await.with_context(|| { - format!("Failed to canonicalize settings path {:?}", initial_path) + fs.canonicalize(settings_path).await.with_context(|| { + format!("Failed to canonicalize settings path {:?}", settings_path) })?; fs.atomic_write(resolved_path.clone(), new_text) @@ -428,10 +428,10 @@ impl SettingsStore { format!("Failed to write settings to file {:?}", resolved_path) })?; } else { - fs.atomic_write(initial_path.to_path_buf(), new_text) + fs.atomic_write(settings_path.to_path_buf(), new_text) .await .with_context(|| { - format!("Failed to write settings to file {:?}", initial_path) + format!("Failed to write settings to file {:?}", settings_path) })?; } @@ -1011,17 +1011,16 @@ impl SettingsStore { let Some(new_text) = migrate_settings(&old_text) else { return anyhow::Ok(()); }; - let initial_path = paths::settings_file().as_path(); - if fs.is_file(initial_path).await { - let backup_path = paths::home_dir().join(".zed_settings_backup"); - fs.atomic_write(backup_path, old_text) + let settings_path = paths::settings_file().as_path(); + if fs.is_file(settings_path).await { + fs.atomic_write(paths::settings_backup_file().to_path_buf(), old_text) .await .with_context(|| { "Failed to create settings backup in home directory".to_string() })?; let resolved_path = - fs.canonicalize(initial_path).await.with_context(|| { - format!("Failed to canonicalize settings path {:?}", initial_path) + fs.canonicalize(settings_path).await.with_context(|| { + format!("Failed to canonicalize settings path {:?}", settings_path) })?; fs.atomic_write(resolved_path.clone(), new_text) .await @@ -1029,10 +1028,10 @@ impl SettingsStore { format!("Failed to write settings to file {:?}", resolved_path) })?; } else { - fs.atomic_write(initial_path.to_path_buf(), new_text) + fs.atomic_write(settings_path.to_path_buf(), new_text) .await .with_context(|| { - format!("Failed to write settings to file {:?}", initial_path) + format!("Failed to write settings to file {:?}", settings_path) })?; } anyhow::Ok(()) diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index ad491910d0..797c9754ed 100644 --- a/crates/workspace/src/notifications.rs +++ b/crates/workspace/src/notifications.rs @@ -448,6 +448,14 @@ pub mod simple_message_notification { self } + pub fn primary_on_click_arc(mut self, on_click: Arc) -> Self + where + F: 'static + Fn(&mut Window, &mut Context), + { + self.primary_on_click = Some(on_click); + self + } + pub fn secondary_message(mut self, message: S) -> Self where S: Into, @@ -474,6 +482,14 @@ pub mod simple_message_notification { self } + pub fn secondary_on_click_arc(mut self, on_click: Arc) -> Self + where + F: 'static + Fn(&mut Window, &mut Context), + { + self.secondary_on_click = Some(on_click); + self + } + pub fn more_info_message(mut self, message: S) -> Self where S: Into, diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 9d4cb83e08..7fe30db8fe 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -1217,25 +1217,29 @@ fn show_keymap_migration_notification_if_needed( if !KeymapFile::should_migrate_keymap(keymap_file) { return false; } - show_app_notification(notification_id, cx, move |cx| { - cx.new(move |_cx| { - let message = "A newer version of Zed has simplified several keymaps. Your existing keymaps may be deprecated. You can migrate them by clicking below. A backup will be created in your home directory."; - let button_text = "Backup and Migrate Keymap"; - MessageNotification::new_from_builder(move |_, _| { - gpui::div().text_xs().child(message).into_any() - }) - .primary_message(button_text) - .primary_on_click(move |_, cx| { - let fs = ::global(cx); - cx.spawn(move |weak_notification, mut cx| async move { - KeymapFile::migrate_keymap(fs).await.ok(); - weak_notification.update(&mut cx, |_, cx| { + let message = MarkdownString(format!( + "Keymap migration needed, as the format for some actions has changed. \ + You can migrate your keymap by clicking below. A backup will be created at {}.", + MarkdownString::inline_code(&paths::keymap_backup_file().to_string_lossy()) + )); + show_markdown_app_notification( + notification_id, + message, + "Backup and Migrate Keymap".into(), + move |_, cx| { + let fs = ::global(cx); + cx.spawn(move |weak_notification, mut cx| async move { + KeymapFile::migrate_keymap(fs).await.ok(); + weak_notification + .update(&mut cx, |_, cx| { cx.emit(DismissEvent); - }).ok(); - }).detach(); + }) + .ok(); }) - }) - }); + .detach(); + }, + cx, + ); return true; } @@ -1247,33 +1251,55 @@ fn show_settings_migration_notification_if_needed( if !SettingsStore::should_migrate_settings(&settings) { return; } - show_app_notification(notification_id, cx, move |cx| { - cx.new(move |_cx| { - let message = "A newer version of Zed has updated some settings. Your existing settings may be deprecated. You can migrate them by clicking below. A backup will be created in your home directory."; - let button_text = "Backup and Migrate Settings"; - MessageNotification::new_from_builder(move |_, _| { - gpui::div().text_xs().child(message).into_any() - }) - .primary_message(button_text) - .primary_on_click(move |_, cx| { - let fs = ::global(cx); - cx.update_global(|store: &mut SettingsStore, _| store.migrate_settings(fs)); - cx.emit(DismissEvent); - }) - }) - }); + let message = MarkdownString(format!( + "Settings migration needed, as the format for some settings has changed. \ + You can migrate your settings by clicking below. A backup will be created at {}.", + MarkdownString::inline_code(&paths::settings_backup_file().to_string_lossy()) + )); + show_markdown_app_notification( + notification_id, + message, + "Backup and Migrate Settings".into(), + move |_, cx| { + let fs = ::global(cx); + cx.update_global(|store: &mut SettingsStore, _| store.migrate_settings(fs)); + cx.emit(DismissEvent); + }, + cx, + ); } fn show_keymap_file_load_error( notification_id: NotificationId, - markdown_error_message: MarkdownString, + error_message: MarkdownString, cx: &mut App, ) { + show_markdown_app_notification( + notification_id.clone(), + error_message, + "Open Keymap File".into(), + |window, cx| { + window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx); + cx.emit(DismissEvent); + }, + cx, + ) +} + +fn show_markdown_app_notification( + notification_id: NotificationId, + message: MarkdownString, + primary_button_message: SharedString, + primary_button_on_click: F, + cx: &mut App, +) where + F: 'static + Send + Sync + Fn(&mut Window, &mut Context), +{ let parsed_markdown = cx.background_executor().spawn(async move { let file_location_directory = None; let language_registry = None; markdown_preview::markdown_parser::parse_markdown( - &markdown_error_message.0, + &message.0, file_location_directory, language_registry, ) @@ -1282,10 +1308,14 @@ fn show_keymap_file_load_error( cx.spawn(move |cx| async move { let parsed_markdown = Arc::new(parsed_markdown.await); + let primary_button_message = primary_button_message.clone(); + let primary_button_on_click = Arc::new(primary_button_on_click); cx.update(|cx| { show_app_notification(notification_id, cx, move |cx| { let workspace_handle = cx.entity().downgrade(); let parsed_markdown = parsed_markdown.clone(); + let primary_button_message = primary_button_message.clone(); + let primary_button_on_click = primary_button_on_click.clone(); cx.new(move |_cx| { MessageNotification::new_from_builder(move |window, cx| { gpui::div() @@ -1298,11 +1328,8 @@ fn show_keymap_file_load_error( )) .into_any() }) - .primary_message("Open Keymap File") - .primary_on_click(|window, cx| { - window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx); - cx.emit(DismissEvent); - }) + .primary_message(primary_button_message) + .primary_on_click_arc(primary_button_on_click) }) }) })