onboarding: Wire up settings import (#35366)
Closes #ISSUE Release Notes: - N/A *or* Added/Fixed/Improved ...
This commit is contained in:
parent
cdce3b3620
commit
afcb8f2a3f
7 changed files with 147 additions and 129 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -10982,12 +10982,16 @@ dependencies = [
|
||||||
"gpui",
|
"gpui",
|
||||||
"language",
|
"language",
|
||||||
"project",
|
"project",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
"settings",
|
"settings",
|
||||||
"theme",
|
"theme",
|
||||||
"ui",
|
"ui",
|
||||||
|
"util",
|
||||||
"workspace",
|
"workspace",
|
||||||
"workspace-hack",
|
"workspace-hack",
|
||||||
"zed_actions",
|
"zed_actions",
|
||||||
|
"zlog",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -14773,7 +14777,6 @@ dependencies = [
|
||||||
"notifications",
|
"notifications",
|
||||||
"paths",
|
"paths",
|
||||||
"project",
|
"project",
|
||||||
"schemars",
|
|
||||||
"search",
|
"search",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
|
@ -24,9 +24,13 @@ fs.workspace = true
|
||||||
gpui.workspace = true
|
gpui.workspace = true
|
||||||
language.workspace = true
|
language.workspace = true
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
|
schemars.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
settings.workspace = true
|
settings.workspace = true
|
||||||
theme.workspace = true
|
theme.workspace = true
|
||||||
ui.workspace = true
|
ui.workspace = true
|
||||||
|
util.workspace = true
|
||||||
workspace-hack.workspace = true
|
workspace-hack.workspace = true
|
||||||
workspace.workspace = true
|
workspace.workspace = true
|
||||||
zed_actions.workspace = true
|
zed_actions.workspace = true
|
||||||
|
zlog.workspace = true
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
use editor::{EditorSettings, ShowMinimap};
|
use editor::{EditorSettings, ShowMinimap};
|
||||||
use fs::Fs;
|
use fs::Fs;
|
||||||
use gpui::{App, IntoElement, Pixels, Window};
|
use gpui::{Action, App, IntoElement, Pixels, Window};
|
||||||
use language::language_settings::AllLanguageSettings;
|
use language::language_settings::AllLanguageSettings;
|
||||||
use project::project_settings::ProjectSettings;
|
use project::project_settings::ProjectSettings;
|
||||||
use settings::{Settings as _, update_settings_file};
|
use settings::{Settings as _, update_settings_file};
|
||||||
use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
|
use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
|
||||||
use ui::{
|
use ui::{
|
||||||
ContextMenu, DropdownMenu, IconButton, Label, LabelCommon, LabelSize, NumericStepper,
|
Clickable, ContextMenu, DropdownMenu, IconButton, Label, LabelCommon, LabelSize,
|
||||||
ParentElement, SharedString, Styled, SwitchColor, SwitchField, ToggleButtonGroup,
|
NumericStepper, ParentElement, SharedString, Styled, SwitchColor, SwitchField,
|
||||||
ToggleButtonGroupStyle, ToggleButtonSimple, ToggleState, div, h_flex, px, v_flex,
|
ToggleButtonGroup, ToggleButtonGroupStyle, ToggleButtonSimple, ToggleState, div, h_flex, px,
|
||||||
|
v_flex,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::{ImportCursorSettings, ImportVsCodeSettings};
|
||||||
|
|
||||||
fn read_show_mini_map(cx: &App) -> ShowMinimap {
|
fn read_show_mini_map(cx: &App) -> ShowMinimap {
|
||||||
editor::EditorSettings::get_global(cx).minimap.show
|
editor::EditorSettings::get_global(cx).minimap.show
|
||||||
}
|
}
|
||||||
|
@ -110,14 +113,22 @@ pub(crate) fn render_editing_page(window: &mut Window, cx: &mut App) -> impl Int
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.child(IconButton::new(
|
.child(
|
||||||
"import-vs-code-settings",
|
IconButton::new("import-vs-code-settings", ui::IconName::Code).on_click(
|
||||||
ui::IconName::Code,
|
|_, window, cx| {
|
||||||
))
|
window
|
||||||
.child(IconButton::new(
|
.dispatch_action(ImportVsCodeSettings::default().boxed_clone(), cx)
|
||||||
"import-cursor-settings",
|
},
|
||||||
ui::IconName::CursorIBeam,
|
),
|
||||||
)),
|
)
|
||||||
|
.child(
|
||||||
|
IconButton::new("import-cursor-settings", ui::IconName::CursorIBeam).on_click(
|
||||||
|
|_, window, cx| {
|
||||||
|
window
|
||||||
|
.dispatch_action(ImportCursorSettings::default().boxed_clone(), cx)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.child(Label::new("Popular Settings").size(LabelSize::Large))
|
.child(Label::new("Popular Settings").size(LabelSize::Large))
|
||||||
.child(
|
.child(
|
||||||
|
|
|
@ -4,10 +4,13 @@ use db::kvp::KEY_VALUE_STORE;
|
||||||
use feature_flags::{FeatureFlag, FeatureFlagViewExt as _};
|
use feature_flags::{FeatureFlag, FeatureFlagViewExt as _};
|
||||||
use fs::Fs;
|
use fs::Fs;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable,
|
Action, AnyElement, App, AppContext, AsyncWindowContext, Context, Entity, EventEmitter,
|
||||||
IntoElement, Render, SharedString, Subscription, Task, WeakEntity, Window, actions,
|
FocusHandle, Focusable, IntoElement, Render, SharedString, Subscription, Task, WeakEntity,
|
||||||
|
Window, actions,
|
||||||
};
|
};
|
||||||
use settings::{Settings, SettingsStore, update_settings_file};
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use settings::{Settings, SettingsStore, VsCodeSettingsSource, update_settings_file};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use theme::{ThemeMode, ThemeSettings};
|
use theme::{ThemeMode, ThemeSettings};
|
||||||
use ui::{
|
use ui::{
|
||||||
|
@ -30,6 +33,24 @@ impl FeatureFlag for OnBoardingFeatureFlag {
|
||||||
const NAME: &'static str = "onboarding";
|
const NAME: &'static str = "onboarding";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Imports settings from Visual Studio Code.
|
||||||
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Deserialize, JsonSchema, Action)]
|
||||||
|
#[action(namespace = zed)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct ImportVsCodeSettings {
|
||||||
|
#[serde(default)]
|
||||||
|
pub skip_prompt: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Imports settings from Cursor editor.
|
||||||
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Deserialize, JsonSchema, Action)]
|
||||||
|
#[action(namespace = zed)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct ImportCursorSettings {
|
||||||
|
#[serde(default)]
|
||||||
|
pub skip_prompt: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub const FIRST_OPEN: &str = "first_open";
|
pub const FIRST_OPEN: &str = "first_open";
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
|
@ -95,6 +116,43 @@ pub fn init(cx: &mut App) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cx.observe_new(|workspace: &mut Workspace, _window, _cx| {
|
||||||
|
workspace.register_action(|_workspace, action: &ImportVsCodeSettings, window, cx| {
|
||||||
|
let fs = <dyn Fs>::global(cx);
|
||||||
|
let action = *action;
|
||||||
|
|
||||||
|
window
|
||||||
|
.spawn(cx, async move |cx: &mut AsyncWindowContext| {
|
||||||
|
handle_import_vscode_settings(
|
||||||
|
VsCodeSettingsSource::VsCode,
|
||||||
|
action.skip_prompt,
|
||||||
|
fs,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
});
|
||||||
|
|
||||||
|
workspace.register_action(|_workspace, action: &ImportCursorSettings, window, cx| {
|
||||||
|
let fs = <dyn Fs>::global(cx);
|
||||||
|
let action = *action;
|
||||||
|
|
||||||
|
window
|
||||||
|
.spawn(cx, async move |cx: &mut AsyncWindowContext| {
|
||||||
|
handle_import_vscode_settings(
|
||||||
|
VsCodeSettingsSource::Cursor,
|
||||||
|
action.skip_prompt,
|
||||||
|
fs,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
|
||||||
cx.observe_new::<Workspace>(|_, window, cx| {
|
cx.observe_new::<Workspace>(|_, window, cx| {
|
||||||
let Some(window) = window else {
|
let Some(window) = window else {
|
||||||
return;
|
return;
|
||||||
|
@ -371,3 +429,54 @@ impl Item for Onboarding {
|
||||||
f(*event)
|
f(*event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn handle_import_vscode_settings(
|
||||||
|
source: VsCodeSettingsSource,
|
||||||
|
skip_prompt: bool,
|
||||||
|
fs: Arc<dyn Fs>,
|
||||||
|
cx: &mut AsyncWindowContext,
|
||||||
|
) {
|
||||||
|
use util::truncate_and_remove_front;
|
||||||
|
|
||||||
|
let vscode_settings =
|
||||||
|
match settings::VsCodeSettings::load_user_settings(source, fs.clone()).await {
|
||||||
|
Ok(vscode_settings) => vscode_settings,
|
||||||
|
Err(err) => {
|
||||||
|
zlog::error!("{err}");
|
||||||
|
let _ = cx.prompt(
|
||||||
|
gpui::PromptLevel::Info,
|
||||||
|
&format!("Could not find or load a {source} settings file"),
|
||||||
|
None,
|
||||||
|
&["Ok"],
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !skip_prompt {
|
||||||
|
let prompt = cx.prompt(
|
||||||
|
gpui::PromptLevel::Warning,
|
||||||
|
&format!(
|
||||||
|
"Importing {} settings may overwrite your existing settings. \
|
||||||
|
Will import settings from {}",
|
||||||
|
vscode_settings.source,
|
||||||
|
truncate_and_remove_front(&vscode_settings.path.to_string_lossy(), 128),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
&["Ok", "Cancel"],
|
||||||
|
);
|
||||||
|
let result = cx.spawn(async move |_| prompt.await.ok()).await;
|
||||||
|
if result != Some(0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cx.update(|_, cx| {
|
||||||
|
let source = vscode_settings.source;
|
||||||
|
let path = vscode_settings.path.clone();
|
||||||
|
cx.global::<SettingsStore>()
|
||||||
|
.import_vscode_settings(fs, vscode_settings);
|
||||||
|
zlog::info!("Imported {source} settings from {}", path.display());
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
|
@ -532,7 +532,9 @@ impl SettingsStore {
|
||||||
}))
|
}))
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SettingsStore {
|
||||||
/// Updates the value of a setting in a JSON file, returning the new text
|
/// Updates the value of a setting in a JSON file, returning the new text
|
||||||
/// for that JSON file.
|
/// for that JSON file.
|
||||||
pub fn new_text_for_update<T: Settings>(
|
pub fn new_text_for_update<T: Settings>(
|
||||||
|
|
|
@ -30,7 +30,6 @@ menu.workspace = true
|
||||||
notifications.workspace = true
|
notifications.workspace = true
|
||||||
paths.workspace = true
|
paths.workspace = true
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
schemars.workspace = true
|
|
||||||
search.workspace = true
|
search.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
|
|
@ -1,20 +1,12 @@
|
||||||
mod appearance_settings_controls;
|
mod appearance_settings_controls;
|
||||||
|
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use command_palette_hooks::CommandPaletteFilter;
|
use command_palette_hooks::CommandPaletteFilter;
|
||||||
use editor::EditorSettingsControls;
|
use editor::EditorSettingsControls;
|
||||||
use feature_flags::{FeatureFlag, FeatureFlagViewExt};
|
use feature_flags::{FeatureFlag, FeatureFlagViewExt};
|
||||||
use fs::Fs;
|
use gpui::{App, Entity, EventEmitter, FocusHandle, Focusable, actions};
|
||||||
use gpui::{
|
|
||||||
Action, App, AsyncWindowContext, Entity, EventEmitter, FocusHandle, Focusable, Task, actions,
|
|
||||||
};
|
|
||||||
use schemars::JsonSchema;
|
|
||||||
use serde::Deserialize;
|
|
||||||
use settings::{SettingsStore, VsCodeSettingsSource};
|
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
use util::truncate_and_remove_front;
|
|
||||||
use workspace::item::{Item, ItemEvent};
|
use workspace::item::{Item, ItemEvent};
|
||||||
use workspace::{Workspace, with_active_or_new_workspace};
|
use workspace::{Workspace, with_active_or_new_workspace};
|
||||||
|
|
||||||
|
@ -29,23 +21,6 @@ impl FeatureFlag for SettingsUiFeatureFlag {
|
||||||
const NAME: &'static str = "settings-ui";
|
const NAME: &'static str = "settings-ui";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Imports settings from Visual Studio Code.
|
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Deserialize, JsonSchema, Action)]
|
|
||||||
#[action(namespace = zed)]
|
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
pub struct ImportVsCodeSettings {
|
|
||||||
#[serde(default)]
|
|
||||||
pub skip_prompt: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Imports settings from Cursor editor.
|
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Deserialize, JsonSchema, Action)]
|
|
||||||
#[action(namespace = zed)]
|
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
pub struct ImportCursorSettings {
|
|
||||||
#[serde(default)]
|
|
||||||
pub skip_prompt: bool,
|
|
||||||
}
|
|
||||||
actions!(
|
actions!(
|
||||||
zed,
|
zed,
|
||||||
[
|
[
|
||||||
|
@ -72,45 +47,11 @@ pub fn init(cx: &mut App) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.observe_new(|workspace: &mut Workspace, window, cx| {
|
cx.observe_new(|_workspace: &mut Workspace, window, cx| {
|
||||||
let Some(window) = window else {
|
let Some(window) = window else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
workspace.register_action(|_workspace, action: &ImportVsCodeSettings, window, cx| {
|
|
||||||
let fs = <dyn Fs>::global(cx);
|
|
||||||
let action = *action;
|
|
||||||
|
|
||||||
window
|
|
||||||
.spawn(cx, async move |cx: &mut AsyncWindowContext| {
|
|
||||||
handle_import_vscode_settings(
|
|
||||||
VsCodeSettingsSource::VsCode,
|
|
||||||
action.skip_prompt,
|
|
||||||
fs,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
});
|
|
||||||
|
|
||||||
workspace.register_action(|_workspace, action: &ImportCursorSettings, window, cx| {
|
|
||||||
let fs = <dyn Fs>::global(cx);
|
|
||||||
let action = *action;
|
|
||||||
|
|
||||||
window
|
|
||||||
.spawn(cx, async move |cx: &mut AsyncWindowContext| {
|
|
||||||
handle_import_vscode_settings(
|
|
||||||
VsCodeSettingsSource::Cursor,
|
|
||||||
action.skip_prompt,
|
|
||||||
fs,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
});
|
|
||||||
|
|
||||||
let settings_ui_actions = [TypeId::of::<OpenSettingsEditor>()];
|
let settings_ui_actions = [TypeId::of::<OpenSettingsEditor>()];
|
||||||
|
|
||||||
CommandPaletteFilter::update_global(cx, |filter, _cx| {
|
CommandPaletteFilter::update_global(cx, |filter, _cx| {
|
||||||
|
@ -138,57 +79,6 @@ pub fn init(cx: &mut App) {
|
||||||
keybindings::init(cx);
|
keybindings::init(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_import_vscode_settings(
|
|
||||||
source: VsCodeSettingsSource,
|
|
||||||
skip_prompt: bool,
|
|
||||||
fs: Arc<dyn Fs>,
|
|
||||||
cx: &mut AsyncWindowContext,
|
|
||||||
) {
|
|
||||||
let vscode_settings =
|
|
||||||
match settings::VsCodeSettings::load_user_settings(source, fs.clone()).await {
|
|
||||||
Ok(vscode_settings) => vscode_settings,
|
|
||||||
Err(err) => {
|
|
||||||
log::error!("{err}");
|
|
||||||
let _ = cx.prompt(
|
|
||||||
gpui::PromptLevel::Info,
|
|
||||||
&format!("Could not find or load a {source} settings file"),
|
|
||||||
None,
|
|
||||||
&["Ok"],
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let prompt = if skip_prompt {
|
|
||||||
Task::ready(Some(0))
|
|
||||||
} else {
|
|
||||||
let prompt = cx.prompt(
|
|
||||||
gpui::PromptLevel::Warning,
|
|
||||||
&format!(
|
|
||||||
"Importing {} settings may overwrite your existing settings. \
|
|
||||||
Will import settings from {}",
|
|
||||||
vscode_settings.source,
|
|
||||||
truncate_and_remove_front(&vscode_settings.path.to_string_lossy(), 128),
|
|
||||||
),
|
|
||||||
None,
|
|
||||||
&["Ok", "Cancel"],
|
|
||||||
);
|
|
||||||
cx.spawn(async move |_| prompt.await.ok())
|
|
||||||
};
|
|
||||||
if prompt.await != Some(0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.update(|_, cx| {
|
|
||||||
let source = vscode_settings.source;
|
|
||||||
let path = vscode_settings.path.clone();
|
|
||||||
cx.global::<SettingsStore>()
|
|
||||||
.import_vscode_settings(fs, vscode_settings);
|
|
||||||
log::info!("Imported {source} settings from {}", path.display());
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SettingsPage {
|
pub struct SettingsPage {
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue