Migrate keymap and settings + edit predictions rename (#23834)
- [x] snake case keymap properties - [x] flatten actions - [x] keymap migration + notfication - [x] settings migration + notification - [x] inline completions -> edit predictions ### future: - keymap notification doesn't show up on start up, only on keymap save. this is existing bug in zed, will be addressed in seperate PR. Release Notes: - Added a notification for deprecated settings and keymaps, allowing you to migrate them with a single click. A backup of your existing keymap and settings will be created in your home directory. - Modified some keymap actions and settings for consistency. --------- Co-authored-by: Piotr Osiewicz <piotr@zed.dev> Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
a1544f47ad
commit
00c2a30059
58 changed files with 2106 additions and 617 deletions
|
@ -20,6 +20,7 @@ use command_palette_hooks::CommandPaletteFilter;
|
|||
use editor::ProposedChangesEditorToolbar;
|
||||
use editor::{scroll::Autoscroll, Editor, MultiBuffer};
|
||||
use feature_flags::{FeatureFlagAppExt, FeatureFlagViewExt, GitUiFeatureFlag};
|
||||
use fs::Fs;
|
||||
use futures::{channel::mpsc, select_biased, StreamExt};
|
||||
use gpui::{
|
||||
actions, point, px, Action, App, AppContext as _, AsyncApp, Context, DismissEvent, Element,
|
||||
|
@ -1144,18 +1145,34 @@ pub fn handle_keymap_file_changes(
|
|||
cx.update(|cx| {
|
||||
let load_result = KeymapFile::load(&user_keymap_content, cx);
|
||||
match load_result {
|
||||
KeymapFileLoadResult::Success { key_bindings } => {
|
||||
KeymapFileLoadResult::Success {
|
||||
key_bindings,
|
||||
keymap_file,
|
||||
} => {
|
||||
reload_keymaps(cx, key_bindings);
|
||||
dismiss_app_notification(¬ification_id, cx);
|
||||
show_keymap_migration_notification_if_needed(
|
||||
keymap_file,
|
||||
notification_id.clone(),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
KeymapFileLoadResult::SomeFailedToLoad {
|
||||
key_bindings,
|
||||
keymap_file,
|
||||
error_message,
|
||||
} => {
|
||||
if !key_bindings.is_empty() {
|
||||
reload_keymaps(cx, key_bindings);
|
||||
}
|
||||
show_keymap_file_load_error(notification_id.clone(), error_message, cx)
|
||||
dismiss_app_notification(¬ification_id, cx);
|
||||
if !show_keymap_migration_notification_if_needed(
|
||||
keymap_file,
|
||||
notification_id.clone(),
|
||||
cx,
|
||||
) {
|
||||
show_keymap_file_load_error(notification_id.clone(), error_message, cx);
|
||||
}
|
||||
}
|
||||
KeymapFileLoadResult::JsonParseFailure { error } => {
|
||||
show_keymap_file_json_error(notification_id.clone(), &error, cx)
|
||||
|
@ -1187,6 +1204,61 @@ fn show_keymap_file_json_error(
|
|||
});
|
||||
}
|
||||
|
||||
fn show_keymap_migration_notification_if_needed(
|
||||
keymap_file: KeymapFile,
|
||||
notification_id: NotificationId,
|
||||
cx: &mut App,
|
||||
) -> bool {
|
||||
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 = <dyn 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();
|
||||
})
|
||||
})
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
fn show_settings_migration_notification_if_needed(
|
||||
notification_id: NotificationId,
|
||||
settings: serde_json::Value,
|
||||
cx: &mut App,
|
||||
) {
|
||||
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 = <dyn Fs>::global(cx);
|
||||
cx.update_global(|store: &mut SettingsStore, _| store.migrate_settings(fs));
|
||||
cx.emit(DismissEvent);
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn show_keymap_file_load_error(
|
||||
notification_id: NotificationId,
|
||||
markdown_error_message: MarkdownString,
|
||||
|
@ -1259,12 +1331,12 @@ pub fn load_default_keymap(cx: &mut App) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn handle_settings_changed(error: Option<anyhow::Error>, cx: &mut App) {
|
||||
pub fn handle_settings_changed(result: Result<serde_json::Value, anyhow::Error>, cx: &mut App) {
|
||||
struct SettingsParseErrorNotification;
|
||||
let id = NotificationId::unique::<SettingsParseErrorNotification>();
|
||||
|
||||
match error {
|
||||
Some(error) => {
|
||||
match result {
|
||||
Err(error) => {
|
||||
if let Some(InvalidSettingsError::LocalSettings { .. }) =
|
||||
error.downcast_ref::<InvalidSettingsError>()
|
||||
{
|
||||
|
@ -1283,7 +1355,10 @@ pub fn handle_settings_changed(error: Option<anyhow::Error>, cx: &mut App) {
|
|||
})
|
||||
});
|
||||
}
|
||||
None => dismiss_app_notification(&id, cx),
|
||||
Ok(settings) => {
|
||||
dismiss_app_notification(&id, cx);
|
||||
show_settings_migration_notification_if_needed(id, settings, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3925,24 +4000,28 @@ mod tests {
|
|||
"vim::FindCommand"
|
||||
| "vim::Literal"
|
||||
| "vim::ResizePane"
|
||||
| "vim::SwitchMode"
|
||||
| "vim::PushOperator"
|
||||
| "vim::PushObject"
|
||||
| "vim::PushFindForward"
|
||||
| "vim::PushFindBackward"
|
||||
| "vim::PushSneak"
|
||||
| "vim::PushSneakBackward"
|
||||
| "vim::PushChangeSurrounds"
|
||||
| "vim::PushJump"
|
||||
| "vim::PushDigraph"
|
||||
| "vim::PushLiteral"
|
||||
| "vim::Number"
|
||||
| "vim::SelectRegister"
|
||||
| "terminal::SendText"
|
||||
| "terminal::SendKeystroke"
|
||||
| "app_menu::OpenApplicationMenu"
|
||||
| "app_menu::NavigateApplicationMenuInDirection"
|
||||
| "picker::ConfirmInput"
|
||||
| "editor::HandleInput"
|
||||
| "editor::FoldAtLevel"
|
||||
| "pane::ActivateItem"
|
||||
| "workspace::ActivatePane"
|
||||
| "workspace::ActivatePaneInDirection"
|
||||
| "workspace::MoveItemToPane"
|
||||
| "workspace::MoveItemToPaneInDirection"
|
||||
| "workspace::OpenTerminal"
|
||||
| "workspace::SwapPaneInDirection"
|
||||
| "workspace::SendKeystrokes"
|
||||
| "zed::OpenBrowser"
|
||||
| "zed::OpenZedUrl" => {}
|
||||
|
|
|
@ -4,7 +4,7 @@ use copilot::{Copilot, CopilotCompletionProvider};
|
|||
use editor::{Editor, EditorMode};
|
||||
use feature_flags::{FeatureFlagAppExt, PredictEditsFeatureFlag};
|
||||
use gpui::{AnyWindowHandle, App, AppContext, Context, Entity, WeakEntity};
|
||||
use language::language_settings::{all_language_settings, InlineCompletionProvider};
|
||||
use language::language_settings::{all_language_settings, EditPredictionProvider};
|
||||
use settings::SettingsStore;
|
||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
||||
use supermaven::{Supermaven, SupermavenCompletionProvider};
|
||||
|
@ -41,8 +41,8 @@ pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
|
|||
editors
|
||||
.borrow_mut()
|
||||
.insert(editor_handle, window.window_handle());
|
||||
let provider = all_language_settings(None, cx).inline_completions.provider;
|
||||
assign_inline_completion_provider(
|
||||
let provider = all_language_settings(None, cx).edit_predictions.provider;
|
||||
assign_edit_prediction_provider(
|
||||
editor,
|
||||
provider,
|
||||
&client,
|
||||
|
@ -54,11 +54,11 @@ pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
|
|||
})
|
||||
.detach();
|
||||
|
||||
let mut provider = all_language_settings(None, cx).inline_completions.provider;
|
||||
let mut provider = all_language_settings(None, cx).edit_predictions.provider;
|
||||
for (editor, window) in editors.borrow().iter() {
|
||||
_ = window.update(cx, |_window, window, cx| {
|
||||
_ = editor.update(cx, |editor, cx| {
|
||||
assign_inline_completion_provider(
|
||||
assign_edit_prediction_provider(
|
||||
editor,
|
||||
provider,
|
||||
&client,
|
||||
|
@ -79,8 +79,8 @@ pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
|
|||
let client = client.clone();
|
||||
let user_store = user_store.clone();
|
||||
move |active, cx| {
|
||||
let provider = all_language_settings(None, cx).inline_completions.provider;
|
||||
assign_inline_completion_providers(&editors, provider, &client, user_store.clone(), cx);
|
||||
let provider = all_language_settings(None, cx).edit_predictions.provider;
|
||||
assign_edit_prediction_providers(&editors, provider, &client, user_store.clone(), cx);
|
||||
if active && !cx.is_action_available(&zeta::ClearHistory) {
|
||||
cx.on_action(clear_zeta_edit_history);
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
|
|||
let client = client.clone();
|
||||
let user_store = user_store.clone();
|
||||
move |cx| {
|
||||
let new_provider = all_language_settings(None, cx).inline_completions.provider;
|
||||
let new_provider = all_language_settings(None, cx).edit_predictions.provider;
|
||||
|
||||
if new_provider != provider {
|
||||
let tos_accepted = user_store
|
||||
|
@ -109,7 +109,7 @@ pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
|
|||
);
|
||||
|
||||
provider = new_provider;
|
||||
assign_inline_completion_providers(
|
||||
assign_edit_prediction_providers(
|
||||
&editors,
|
||||
provider,
|
||||
&client,
|
||||
|
@ -119,7 +119,7 @@ pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
|
|||
|
||||
if !tos_accepted {
|
||||
match provider {
|
||||
InlineCompletionProvider::Zed => {
|
||||
EditPredictionProvider::Zed => {
|
||||
let Some(window) = cx.active_window() else {
|
||||
return;
|
||||
};
|
||||
|
@ -133,9 +133,9 @@ pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
|
|||
})
|
||||
.ok();
|
||||
}
|
||||
InlineCompletionProvider::None
|
||||
| InlineCompletionProvider::Copilot
|
||||
| InlineCompletionProvider::Supermaven => {}
|
||||
EditPredictionProvider::None
|
||||
| EditPredictionProvider::Copilot
|
||||
| EditPredictionProvider::Supermaven => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,9 +150,9 @@ fn clear_zeta_edit_history(_: &zeta::ClearHistory, cx: &mut App) {
|
|||
}
|
||||
}
|
||||
|
||||
fn assign_inline_completion_providers(
|
||||
fn assign_edit_prediction_providers(
|
||||
editors: &Rc<RefCell<HashMap<WeakEntity<Editor>, AnyWindowHandle>>>,
|
||||
provider: InlineCompletionProvider,
|
||||
provider: EditPredictionProvider,
|
||||
client: &Arc<Client>,
|
||||
user_store: Entity<UserStore>,
|
||||
cx: &mut App,
|
||||
|
@ -160,7 +160,7 @@ fn assign_inline_completion_providers(
|
|||
for (editor, window) in editors.borrow().iter() {
|
||||
_ = window.update(cx, |_window, window, cx| {
|
||||
_ = editor.update(cx, |editor, cx| {
|
||||
assign_inline_completion_provider(
|
||||
assign_edit_prediction_provider(
|
||||
editor,
|
||||
provider,
|
||||
&client,
|
||||
|
@ -187,7 +187,7 @@ fn register_backward_compatible_actions(editor: &mut Editor, cx: &mut Context<Ed
|
|||
editor
|
||||
.register_action(cx.listener(
|
||||
|editor, _: &copilot::NextSuggestion, window: &mut Window, cx: &mut Context<Editor>| {
|
||||
editor.next_inline_completion(&Default::default(), window, cx);
|
||||
editor.next_edit_prediction(&Default::default(), window, cx);
|
||||
},
|
||||
))
|
||||
.detach();
|
||||
|
@ -197,7 +197,7 @@ fn register_backward_compatible_actions(editor: &mut Editor, cx: &mut Context<Ed
|
|||
_: &copilot::PreviousSuggestion,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Editor>| {
|
||||
editor.previous_inline_completion(&Default::default(), window, cx);
|
||||
editor.previous_edit_prediction(&Default::default(), window, cx);
|
||||
},
|
||||
))
|
||||
.detach();
|
||||
|
@ -213,9 +213,9 @@ fn register_backward_compatible_actions(editor: &mut Editor, cx: &mut Context<Ed
|
|||
.detach();
|
||||
}
|
||||
|
||||
fn assign_inline_completion_provider(
|
||||
fn assign_edit_prediction_provider(
|
||||
editor: &mut Editor,
|
||||
provider: InlineCompletionProvider,
|
||||
provider: EditPredictionProvider,
|
||||
client: &Arc<Client>,
|
||||
user_store: Entity<UserStore>,
|
||||
window: &mut Window,
|
||||
|
@ -225,8 +225,8 @@ fn assign_inline_completion_provider(
|
|||
let singleton_buffer = editor.buffer().read(cx).as_singleton();
|
||||
|
||||
match provider {
|
||||
InlineCompletionProvider::None => {}
|
||||
InlineCompletionProvider::Copilot => {
|
||||
EditPredictionProvider::None => {}
|
||||
EditPredictionProvider::Copilot => {
|
||||
if let Some(copilot) = Copilot::global(cx) {
|
||||
if let Some(buffer) = singleton_buffer {
|
||||
if buffer.read(cx).file().is_some() {
|
||||
|
@ -236,16 +236,16 @@ fn assign_inline_completion_provider(
|
|||
}
|
||||
}
|
||||
let provider = cx.new(|_| CopilotCompletionProvider::new(copilot));
|
||||
editor.set_inline_completion_provider(Some(provider), window, cx);
|
||||
editor.set_edit_prediction_provider(Some(provider), window, cx);
|
||||
}
|
||||
}
|
||||
InlineCompletionProvider::Supermaven => {
|
||||
EditPredictionProvider::Supermaven => {
|
||||
if let Some(supermaven) = Supermaven::global(cx) {
|
||||
let provider = cx.new(|_| SupermavenCompletionProvider::new(supermaven));
|
||||
editor.set_inline_completion_provider(Some(provider), window, cx);
|
||||
editor.set_edit_prediction_provider(Some(provider), window, cx);
|
||||
}
|
||||
}
|
||||
InlineCompletionProvider::Zed => {
|
||||
EditPredictionProvider::Zed => {
|
||||
if cx.has_flag::<PredictEditsFeatureFlag>()
|
||||
|| (cfg!(debug_assertions) && client.status().borrow().is_connected())
|
||||
{
|
||||
|
@ -280,7 +280,7 @@ fn assign_inline_completion_provider(
|
|||
let provider =
|
||||
cx.new(|_| zeta::ZetaInlineCompletionProvider::new(zeta, data_collection));
|
||||
|
||||
editor.set_inline_completion_provider(Some(provider), window, cx);
|
||||
editor.set_edit_prediction_provider(Some(provider), window, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -301,14 +301,14 @@ impl Render for QuickActionBar {
|
|||
.toggleable(IconPosition::Start, inline_completion_enabled && show_inline_completions)
|
||||
.disabled(!inline_completion_enabled)
|
||||
.action(Some(
|
||||
editor::actions::ToggleInlineCompletions.boxed_clone(),
|
||||
editor::actions::ToggleEditPrediction.boxed_clone(),
|
||||
)).handler({
|
||||
let editor = editor.clone();
|
||||
move |window, cx| {
|
||||
editor
|
||||
.update(cx, |editor, cx| {
|
||||
editor.toggle_inline_completions(
|
||||
&editor::actions::ToggleInlineCompletions,
|
||||
&editor::actions::ToggleEditPrediction,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue