Settings/keymap backup path next to files + update notification messages (#24517)
Before:  After:  Release Notes: - N/A
This commit is contained in:
parent
cf74d653bd
commit
1a133ab9d8
5 changed files with 116 additions and 62 deletions
|
@ -145,12 +145,24 @@ pub fn settings_file() -> &'static PathBuf {
|
||||||
SETTINGS_FILE.get_or_init(|| config_dir().join("settings.json"))
|
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<PathBuf> = OnceLock::new();
|
||||||
|
SETTINGS_FILE.get_or_init(|| config_dir().join("settings_backup.json"))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the path to the `keymap.json` file.
|
/// Returns the path to the `keymap.json` file.
|
||||||
pub fn keymap_file() -> &'static PathBuf {
|
pub fn keymap_file() -> &'static PathBuf {
|
||||||
static KEYMAP_FILE: OnceLock<PathBuf> = OnceLock::new();
|
static KEYMAP_FILE: OnceLock<PathBuf> = OnceLock::new();
|
||||||
KEYMAP_FILE.get_or_init(|| config_dir().join("keymap.json"))
|
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<PathBuf> = OnceLock::new();
|
||||||
|
KEYMAP_FILE.get_or_init(|| config_dir().join("keymap_backup.json"))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the path to the `tasks.json` file.
|
/// Returns the path to the `tasks.json` file.
|
||||||
pub fn tasks_file() -> &'static PathBuf {
|
pub fn tasks_file() -> &'static PathBuf {
|
||||||
static TASKS_FILE: OnceLock<PathBuf> = OnceLock::new();
|
static TASKS_FILE: OnceLock<PathBuf> = OnceLock::new();
|
||||||
|
|
|
@ -588,24 +588,24 @@ impl KeymapFile {
|
||||||
let Some(new_text) = migrate_keymap(&old_text) else {
|
let Some(new_text) = migrate_keymap(&old_text) else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
let initial_path = paths::keymap_file().as_path();
|
let keymap_path = paths::keymap_file().as_path();
|
||||||
if fs.is_file(initial_path).await {
|
if fs.is_file(keymap_path).await {
|
||||||
let backup_path = paths::home_dir().join(".zed_keymap_backup");
|
fs.atomic_write(paths::keymap_backup_file().to_path_buf(), old_text)
|
||||||
fs.atomic_write(backup_path, old_text)
|
|
||||||
.await
|
.await
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
"Failed to create settings backup in home directory".to_string()
|
"Failed to create settings backup in home directory".to_string()
|
||||||
})?;
|
})?;
|
||||||
let resolved_path = fs.canonicalize(initial_path).await.with_context(|| {
|
let resolved_path = fs
|
||||||
format!("Failed to canonicalize keymap path {:?}", initial_path)
|
.canonicalize(keymap_path)
|
||||||
})?;
|
.await
|
||||||
|
.with_context(|| format!("Failed to canonicalize keymap path {:?}", keymap_path))?;
|
||||||
fs.atomic_write(resolved_path.clone(), new_text)
|
fs.atomic_write(resolved_path.clone(), new_text)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("Failed to write keymap to file {:?}", resolved_path))?;
|
.with_context(|| format!("Failed to write keymap to file {:?}", resolved_path))?;
|
||||||
} else {
|
} else {
|
||||||
fs.atomic_write(initial_path.to_path_buf(), new_text)
|
fs.atomic_write(keymap_path.to_path_buf(), new_text)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("Failed to write keymap to file {:?}", initial_path))?;
|
.with_context(|| format!("Failed to write keymap to file {:?}", keymap_path))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -415,11 +415,11 @@ impl SettingsStore {
|
||||||
let new_text = cx.read_global(|store: &SettingsStore, cx| {
|
let new_text = cx.read_global(|store: &SettingsStore, cx| {
|
||||||
store.new_text_for_update::<T>(old_text, |content| update(content, cx))
|
store.new_text_for_update::<T>(old_text, |content| update(content, cx))
|
||||||
})?;
|
})?;
|
||||||
let initial_path = paths::settings_file().as_path();
|
let settings_path = paths::settings_file().as_path();
|
||||||
if fs.is_file(initial_path).await {
|
if fs.is_file(settings_path).await {
|
||||||
let resolved_path =
|
let resolved_path =
|
||||||
fs.canonicalize(initial_path).await.with_context(|| {
|
fs.canonicalize(settings_path).await.with_context(|| {
|
||||||
format!("Failed to canonicalize settings path {:?}", initial_path)
|
format!("Failed to canonicalize settings path {:?}", settings_path)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
fs.atomic_write(resolved_path.clone(), new_text)
|
fs.atomic_write(resolved_path.clone(), new_text)
|
||||||
|
@ -428,10 +428,10 @@ impl SettingsStore {
|
||||||
format!("Failed to write settings to file {:?}", resolved_path)
|
format!("Failed to write settings to file {:?}", resolved_path)
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
fs.atomic_write(initial_path.to_path_buf(), new_text)
|
fs.atomic_write(settings_path.to_path_buf(), new_text)
|
||||||
.await
|
.await
|
||||||
.with_context(|| {
|
.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 {
|
let Some(new_text) = migrate_settings(&old_text) else {
|
||||||
return anyhow::Ok(());
|
return anyhow::Ok(());
|
||||||
};
|
};
|
||||||
let initial_path = paths::settings_file().as_path();
|
let settings_path = paths::settings_file().as_path();
|
||||||
if fs.is_file(initial_path).await {
|
if fs.is_file(settings_path).await {
|
||||||
let backup_path = paths::home_dir().join(".zed_settings_backup");
|
fs.atomic_write(paths::settings_backup_file().to_path_buf(), old_text)
|
||||||
fs.atomic_write(backup_path, old_text)
|
|
||||||
.await
|
.await
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
"Failed to create settings backup in home directory".to_string()
|
"Failed to create settings backup in home directory".to_string()
|
||||||
})?;
|
})?;
|
||||||
let resolved_path =
|
let resolved_path =
|
||||||
fs.canonicalize(initial_path).await.with_context(|| {
|
fs.canonicalize(settings_path).await.with_context(|| {
|
||||||
format!("Failed to canonicalize settings path {:?}", initial_path)
|
format!("Failed to canonicalize settings path {:?}", settings_path)
|
||||||
})?;
|
})?;
|
||||||
fs.atomic_write(resolved_path.clone(), new_text)
|
fs.atomic_write(resolved_path.clone(), new_text)
|
||||||
.await
|
.await
|
||||||
|
@ -1029,10 +1028,10 @@ impl SettingsStore {
|
||||||
format!("Failed to write settings to file {:?}", resolved_path)
|
format!("Failed to write settings to file {:?}", resolved_path)
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
fs.atomic_write(initial_path.to_path_buf(), new_text)
|
fs.atomic_write(settings_path.to_path_buf(), new_text)
|
||||||
.await
|
.await
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!("Failed to write settings to file {:?}", initial_path)
|
format!("Failed to write settings to file {:?}", settings_path)
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
|
|
|
@ -448,6 +448,14 @@ pub mod simple_message_notification {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn primary_on_click_arc<F>(mut self, on_click: Arc<F>) -> Self
|
||||||
|
where
|
||||||
|
F: 'static + Fn(&mut Window, &mut Context<Self>),
|
||||||
|
{
|
||||||
|
self.primary_on_click = Some(on_click);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn secondary_message<S>(mut self, message: S) -> Self
|
pub fn secondary_message<S>(mut self, message: S) -> Self
|
||||||
where
|
where
|
||||||
S: Into<SharedString>,
|
S: Into<SharedString>,
|
||||||
|
@ -474,6 +482,14 @@ pub mod simple_message_notification {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn secondary_on_click_arc<F>(mut self, on_click: Arc<F>) -> Self
|
||||||
|
where
|
||||||
|
F: 'static + Fn(&mut Window, &mut Context<Self>),
|
||||||
|
{
|
||||||
|
self.secondary_on_click = Some(on_click);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn more_info_message<S>(mut self, message: S) -> Self
|
pub fn more_info_message<S>(mut self, message: S) -> Self
|
||||||
where
|
where
|
||||||
S: Into<SharedString>,
|
S: Into<SharedString>,
|
||||||
|
|
|
@ -1217,25 +1217,29 @@ fn show_keymap_migration_notification_if_needed(
|
||||||
if !KeymapFile::should_migrate_keymap(keymap_file) {
|
if !KeymapFile::should_migrate_keymap(keymap_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
show_app_notification(notification_id, cx, move |cx| {
|
let message = MarkdownString(format!(
|
||||||
cx.new(move |_cx| {
|
"Keymap migration needed, as the format for some actions has changed. \
|
||||||
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.";
|
You can migrate your keymap by clicking below. A backup will be created at {}.",
|
||||||
let button_text = "Backup and Migrate Keymap";
|
MarkdownString::inline_code(&paths::keymap_backup_file().to_string_lossy())
|
||||||
MessageNotification::new_from_builder(move |_, _| {
|
));
|
||||||
gpui::div().text_xs().child(message).into_any()
|
show_markdown_app_notification(
|
||||||
})
|
notification_id,
|
||||||
.primary_message(button_text)
|
message,
|
||||||
.primary_on_click(move |_, cx| {
|
"Backup and Migrate Keymap".into(),
|
||||||
let fs = <dyn Fs>::global(cx);
|
move |_, cx| {
|
||||||
cx.spawn(move |weak_notification, mut cx| async move {
|
let fs = <dyn Fs>::global(cx);
|
||||||
KeymapFile::migrate_keymap(fs).await.ok();
|
cx.spawn(move |weak_notification, mut cx| async move {
|
||||||
weak_notification.update(&mut cx, |_, cx| {
|
KeymapFile::migrate_keymap(fs).await.ok();
|
||||||
|
weak_notification
|
||||||
|
.update(&mut cx, |_, cx| {
|
||||||
cx.emit(DismissEvent);
|
cx.emit(DismissEvent);
|
||||||
}).ok();
|
})
|
||||||
}).detach();
|
.ok();
|
||||||
})
|
})
|
||||||
})
|
.detach();
|
||||||
});
|
},
|
||||||
|
cx,
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1247,33 +1251,55 @@ fn show_settings_migration_notification_if_needed(
|
||||||
if !SettingsStore::should_migrate_settings(&settings) {
|
if !SettingsStore::should_migrate_settings(&settings) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
show_app_notification(notification_id, cx, move |cx| {
|
let message = MarkdownString(format!(
|
||||||
cx.new(move |_cx| {
|
"Settings migration needed, as the format for some settings has changed. \
|
||||||
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.";
|
You can migrate your settings by clicking below. A backup will be created at {}.",
|
||||||
let button_text = "Backup and Migrate Settings";
|
MarkdownString::inline_code(&paths::settings_backup_file().to_string_lossy())
|
||||||
MessageNotification::new_from_builder(move |_, _| {
|
));
|
||||||
gpui::div().text_xs().child(message).into_any()
|
show_markdown_app_notification(
|
||||||
})
|
notification_id,
|
||||||
.primary_message(button_text)
|
message,
|
||||||
.primary_on_click(move |_, cx| {
|
"Backup and Migrate Settings".into(),
|
||||||
let fs = <dyn Fs>::global(cx);
|
move |_, cx| {
|
||||||
cx.update_global(|store: &mut SettingsStore, _| store.migrate_settings(fs));
|
let fs = <dyn Fs>::global(cx);
|
||||||
cx.emit(DismissEvent);
|
cx.update_global(|store: &mut SettingsStore, _| store.migrate_settings(fs));
|
||||||
})
|
cx.emit(DismissEvent);
|
||||||
})
|
},
|
||||||
});
|
cx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_keymap_file_load_error(
|
fn show_keymap_file_load_error(
|
||||||
notification_id: NotificationId,
|
notification_id: NotificationId,
|
||||||
markdown_error_message: MarkdownString,
|
error_message: MarkdownString,
|
||||||
cx: &mut App,
|
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<F>(
|
||||||
|
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<MessageNotification>),
|
||||||
|
{
|
||||||
let parsed_markdown = cx.background_executor().spawn(async move {
|
let parsed_markdown = cx.background_executor().spawn(async move {
|
||||||
let file_location_directory = None;
|
let file_location_directory = None;
|
||||||
let language_registry = None;
|
let language_registry = None;
|
||||||
markdown_preview::markdown_parser::parse_markdown(
|
markdown_preview::markdown_parser::parse_markdown(
|
||||||
&markdown_error_message.0,
|
&message.0,
|
||||||
file_location_directory,
|
file_location_directory,
|
||||||
language_registry,
|
language_registry,
|
||||||
)
|
)
|
||||||
|
@ -1282,10 +1308,14 @@ fn show_keymap_file_load_error(
|
||||||
|
|
||||||
cx.spawn(move |cx| async move {
|
cx.spawn(move |cx| async move {
|
||||||
let parsed_markdown = Arc::new(parsed_markdown.await);
|
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| {
|
cx.update(|cx| {
|
||||||
show_app_notification(notification_id, cx, move |cx| {
|
show_app_notification(notification_id, cx, move |cx| {
|
||||||
let workspace_handle = cx.entity().downgrade();
|
let workspace_handle = cx.entity().downgrade();
|
||||||
let parsed_markdown = parsed_markdown.clone();
|
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| {
|
cx.new(move |_cx| {
|
||||||
MessageNotification::new_from_builder(move |window, cx| {
|
MessageNotification::new_from_builder(move |window, cx| {
|
||||||
gpui::div()
|
gpui::div()
|
||||||
|
@ -1298,11 +1328,8 @@ fn show_keymap_file_load_error(
|
||||||
))
|
))
|
||||||
.into_any()
|
.into_any()
|
||||||
})
|
})
|
||||||
.primary_message("Open Keymap File")
|
.primary_message(primary_button_message)
|
||||||
.primary_on_click(|window, cx| {
|
.primary_on_click_arc(primary_button_on_click)
|
||||||
window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx);
|
|
||||||
cx.emit(DismissEvent);
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue