@@ -22,7 +22,7 @@ pub use settings_store::{
InvalidSettingsError, LocalSettingsKind, Settings, SettingsLocation, SettingsSources,
SettingsStore, parse_json_with_comments,
};
-pub use vscode_import::VsCodeSettings;
+pub use vscode_import::{VsCodeSettings, VsCodeSettingsSource};
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
pub struct WorktreeId(usize);
@@ -1522,6 +1522,8 @@ pub fn parse_json_with_comments<T: DeserializeOwned>(content: &str) -> Result<T>
#[cfg(test)]
mod tests {
+ use crate::VsCodeSettingsSource;
+
use super::*;
use serde_derive::Deserialize;
use unindent::Unindent;
@@ -2004,7 +2006,10 @@ mod tests {
cx: &mut App,
) {
store.set_user_settings(&old, cx).ok();
- let new = store.get_vscode_edits(old, &VsCodeSettings::from_str(&vscode).unwrap());
+ let new = store.get_vscode_edits(
+ old,
+ &VsCodeSettings::from_str(&vscode, VsCodeSettingsSource::VsCode).unwrap(),
+ );
pretty_assertions::assert_eq!(new, expected);
}
@@ -4,20 +4,42 @@ use serde_json::{Map, Value};
use std::sync::Arc;
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum VsCodeSettingsSource {
+ VsCode,
+ Cursor,
+}
+
+impl std::fmt::Display for VsCodeSettingsSource {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ VsCodeSettingsSource::VsCode => write!(f, "VS Code"),
+ VsCodeSettingsSource::Cursor => write!(f, "Cursor"),
+ }
+ }
+}
+
pub struct VsCodeSettings {
+ pub source: VsCodeSettingsSource,
content: Map<String, Value>,
}
impl VsCodeSettings {
- pub fn from_str(content: &str) -> Result<Self> {
+ pub fn from_str(content: &str, source: VsCodeSettingsSource) -> Result<Self> {
Ok(Self {
+ source,
content: serde_json_lenient::from_str(content)?,
})
}
- pub async fn load_user_settings(fs: Arc<dyn Fs>) -> Result<Self> {
- let content = fs.load(paths::vscode_settings_file()).await?;
+ pub async fn load_user_settings(source: VsCodeSettingsSource, fs: Arc<dyn Fs>) -> Result<Self> {
+ let path = match source {
+ VsCodeSettingsSource::VsCode => paths::vscode_settings_file(),
+ VsCodeSettingsSource::Cursor => paths::cursor_settings_file(),
+ };
+ let content = fs.load(path).await?;
Ok(Self {
+ source,
content: serde_json_lenient::from_str(&content)?,
})
}
@@ -1,6 +1,7 @@
mod appearance_settings_controls;
use std::any::TypeId;
+use std::sync::Arc;
use command_palette_hooks::CommandPaletteFilter;
use editor::EditorSettingsControls;
@@ -12,7 +13,7 @@ use gpui::{
};
use schemars::JsonSchema;
use serde::Deserialize;
-use settings::SettingsStore;
+use settings::{SettingsStore, VsCodeSettingsSource};
use ui::prelude::*;
use workspace::Workspace;
use workspace::item::{Item, ItemEvent};
@@ -31,7 +32,13 @@ pub struct ImportVsCodeSettings {
pub skip_prompt: bool,
}
-impl_actions!(zed, [ImportVsCodeSettings]);
+#[derive(Copy, Clone, Debug, Default, PartialEq, Deserialize, JsonSchema)]
+pub struct ImportCursorSettings {
+ #[serde(default)]
+ pub skip_prompt: bool,
+}
+
+impl_actions!(zed, [ImportVsCodeSettings, ImportCursorSettings]);
actions!(zed, [OpenSettingsEditor]);
pub fn init(cx: &mut App) {
@@ -61,49 +68,30 @@ pub fn init(cx: &mut App) {
window
.spawn(cx, async move |cx: &mut AsyncWindowContext| {
- let vscode =
- match settings::VsCodeSettings::load_user_settings(fs.clone()).await {
- Ok(vscode) => vscode,
- Err(err) => {
- println!(
- "Failed to load VsCode settings: {}",
- err.context(format!(
- "Loading VsCode settings from path: {:?}",
- paths::vscode_settings_file()
- ))
- );
-
- let _ = cx.prompt(
- gpui::PromptLevel::Info,
- "Could not find or load a VsCode settings file",
- None,
- &["Ok"],
- );
- return;
- }
- };
-
- let prompt = if action.skip_prompt {
- Task::ready(Some(0))
- } else {
- let prompt = cx.prompt(
- gpui::PromptLevel::Warning,
- "Importing settings may overwrite your existing settings",
- None,
- &["Ok", "Cancel"],
- );
- cx.spawn(async move |_| prompt.await.ok())
- };
- if prompt.await != Some(0) {
- return;
- }
-
- cx.update(|_, cx| {
- cx.global::<SettingsStore>()
- .import_vscode_settings(fs, vscode);
- log::info!("Imported settings from VsCode");
- })
- .ok();
+ 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();
});
@@ -133,6 +121,56 @@ pub fn init(cx: &mut App) {
.detach();
}
+async fn handle_import_vscode_settings(
+ source: VsCodeSettingsSource,
+ skip_prompt: bool,
+ fs: Arc<dyn Fs>,
+ cx: &mut AsyncWindowContext,
+) {
+ let vscode = match settings::VsCodeSettings::load_user_settings(source, fs.clone()).await {
+ Ok(vscode) => vscode,
+ Err(err) => {
+ println!(
+ "Failed to load {source} settings: {}",
+ err.context(format!(
+ "Loading {source} settings from path: {:?}",
+ paths::vscode_settings_file()
+ ))
+ );
+
+ 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,
+ "Importing settings may overwrite your existing settings",
+ None,
+ &["Ok", "Cancel"],
+ );
+ cx.spawn(async move |_| prompt.await.ok())
+ };
+ if prompt.await != Some(0) {
+ return;
+ }
+
+ cx.update(|_, cx| {
+ cx.global::<SettingsStore>()
+ .import_vscode_settings(fs, vscode);
+ log::info!("Imported settings from {source}");
+ })
+ .ok();
+}
+
pub struct SettingsPage {
focus_handle: FocusHandle,
}