use crate::multibuffer_hint::MultibufferHint;use client::{Client, UserStore, zed_urls};use cloud_api_types::Plan;use db::kvp::KeyValueStore;use fs::Fs;use gpui::{ Action, AnyElement, App, AppContext, AsyncWindowContext, Context, Entity, EventEmitter, FocusHandle, Focusable, Global, IntoElement, KeyContext, Render, ScrollHandle, SharedString, Subscription, Task, WeakEntity, Window, actions,};use notifications::status_toast::StatusToast;use project::agent_server_store::AllAgentServersSettings;use schemars::JsonSchema;use serde::Deserialize;use settings::{SettingsStore, VsCodeSettingsSource};use std::sync::Arc;use ui::{ Divider, KeyBinding, ParentElement as _, StatefulInteractiveElement, Vector, VectorName, WithScrollbar as _, prelude::*, rems_from_px,}; pub use workspace::welcome::ShowWelcome;use workspace::welcome::WelcomePage;use workspace::{ AppState, Workspace, WorkspaceId, dock::DockPosition, item::{Item, ItemEvent}, notifications::NotifyResultExt as _, open_new, register_serializable_item, with_active_or_new_workspace,};use zed_actions::OpenOnboarding; mod base_keymap_picker;mod basics_page;pub mod multibuffer_hint;mod theme_preview; /// 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"; actions!( onboarding, [ /// Finish the onboarding process. Finish, /// Sign in while in the onboarding flow. SignIn, /// Open the user account in zed.dev while in the onboarding flow. OpenAccount, /// Resets the welcome screen hints to their initial state. ResetHints ]); pub fn init(cx: &mut App) { cx.observe_new(|workspace: &mut Workspace, _, _cx| { workspace .register_action(|_workspace, _: &ResetHints, _, cx| MultibufferHint::set_count(0, cx)); }) .detach(); cx.on_action(|_: &OpenOnboarding, cx| { with_active_or_new_workspace(cx, |workspace, window, cx| { workspace .with_local_workspace(window, cx, |workspace, window, cx| { let existing = workspace .active_pane() .read(cx) .items() .find_map(|item| item.downcast::<Onboarding>()); if let Some(existing) = existing { workspace.activate_item(&existing, true, true, window, cx); } else { let settings_page = Onboarding::new(workspace, cx); workspace.add_item_to_active_pane( Box::new(settings_page), None, true, window, cx, ) } }) .detach(); }); }); cx.on_action(|_: &ShowWelcome, cx| { with_active_or_new_workspace(cx, |workspace, window, cx| { workspace .with_local_workspace(window, cx, |workspace, window, cx| { let existing = workspace .active_pane() .read(cx) .items() .find_map(|item| item.downcast::<WelcomePage>()); if let Some(existing) = existing { workspace.activate_item(&existing, true, true, window, cx); } else { let settings_page = cx .new(|cx| WelcomePage::new(workspace.weak_handle(), false, window, cx)); workspace.add_item_to_active_pane( Box::new(settings_page), None, true, window, cx, ) } }) .detach(); }); }); 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; let workspace = cx.weak_entity(); window .spawn(cx, async move |cx: &mut AsyncWindowContext| { handle_import_vscode_settings( workspace, 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; let workspace = cx.weak_entity(); window .spawn(cx, async move |cx: &mut AsyncWindowContext| { handle_import_vscode_settings( workspace, VsCodeSettingsSource::Cursor, action.skip_prompt, fs, cx, ) .await }) .detach(); }); }) .detach(); base_keymap_picker::init(cx); register_serializable_item::<Onboarding>(cx); register_serializable_item::<WelcomePage>(cx);} pub fn show_onboarding_view(app_state: Arc<AppState>, cx: &mut App) -> Task<anyhow::Result<()>> { telemetry::event!("Onboarding Page Opened"); open_new( Default::default(), app_state, cx, |workspace, window, cx| { { workspace.toggle_dock(DockPosition::Left, window, cx); let onboarding_page = Onboarding::new(workspace, cx); workspace.add_item_to_center(Box::new(onboarding_page.clone()), window, cx); window.focus(&onboarding_page.focus_handle(cx), cx); cx.notify(); }; let kvp = KeyValueStore::global(cx); db::write_and_log(cx, move || async move { kvp.write_kvp(FIRST_OPEN.to_string(), "false".to_string()) .await }); }, )} struct Onboarding { workspace: WeakEntity<Workspace>, focus_handle: FocusHandle, user_store: Entity<UserStore>, scroll_handle: ScrollHandle, _settings_subscription: Subscription,} impl Onboarding { fn new(workspace: &Workspace, cx: &mut App) -> Entity<Self> { let font_family_cache = theme::FontFamilyCache::global(cx); let installed_agents = cx .global::<SettingsStore>() .get::<AllAgentServersSettings>(None) .clone(); let client = Client::global(cx); let status = *client.status().borrow(); let plan = workspace.user_store().read(cx).plan(); let zed_agent_state = if status.is_signed_out() || matches!( status, client::Status::AuthenticationError | client::Status::ConnectionError ) { "signed_out" } else if status.is_signing_in() { "signing_in" } else { match plan { Some(Plan::ZedPro) => "pro", Some(Plan::ZedProTrial) => "trial", Some(Plan::ZedBusiness) => "business", Some(Plan::ZedVip) => "vip", Some(Plan::ZedStudent) => "student", Some(Plan::ZedFree) | None => "free", } }; let agents_installed = basics_page::FEATURED_AGENT_IDS .iter() .filter(|id| installed_agents.contains_key(**id)) .copied() .collect::<Vec<_>>(); telemetry::event!( "Welcome Agent Setup Viewed", zed_agent = zed_agent_state, agents_installed = agents_installed, ); cx.new(|cx| { cx.spawn(async move |this, cx| { font_family_cache.prefetch(cx).await; this.update(cx, |_, cx| { cx.notify(); }) }) .detach(); Self { workspace: workspace.weak_handle(), focus_handle: cx.focus_handle(), scroll_handle: ScrollHandle::new(), user_store: workspace.user_store().clone(), _settings_subscription: cx .observe_global::<SettingsStore>(move |_, cx| cx.notify()), } }) } fn on_finish(_: &Finish, _: &mut Window, cx: &mut App) { telemetry::event!("Finish Setup"); go_to_welcome_page(cx); } fn handle_sign_in(&mut self, _: &SignIn, window: &mut Window, cx: &mut Context<Self>) { let client = Client::global(cx); let workspace = self.workspace.clone(); window .spawn(cx, async move |mut cx| { client .sign_in_with_optional_connect(true, &cx) .await .notify_workspace_async_err(workspace, &mut cx); }) .detach(); } fn handle_open_account(_: &OpenAccount, _: &mut Window, cx: &mut App) { cx.open_url(&zed_urls::account_url(cx)) } fn render_page(&mut self, cx: &mut Context<Self>) -> AnyElement { crate::basics_page::render_basics_page(&self.user_store, cx).into_any_element() }} impl Render for Onboarding { fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { div() .image_cache(gpui::retain_all("onboarding-page")) .key_context({ let mut ctx = KeyContext::new_with_defaults(); ctx.add("Onboarding"); ctx.add("menu"); ctx }) .track_focus(&self.focus_handle) .size_full() .bg(cx.theme().colors().editor_background) .on_action(Self::on_finish) .on_action(cx.listener(Self::handle_sign_in)) .on_action(Self::handle_open_account) .on_action(cx.listener(|_, _: &menu::SelectNext, window, cx| { window.focus_next(cx); cx.notify(); })) .on_action(cx.listener(|_, _: &menu::SelectPrevious, window, cx| { window.focus_prev(cx); cx.notify(); })) .vertical_scrollbar_for(&self.scroll_handle, window, cx) .child( div() .id("page-content") .size_full() .overflow_y_scroll() .child( v_flex() .min_w_0() .max_w(rems_from_px(780.)) .w_full() .mx_auto() .p_12() .gap_6() .child( h_flex() .w_full() .gap_4() .justify_between() .child( h_flex() .gap_4() .child(Vector::square(VectorName::ZedLogo, rems(2.5))) .child( v_flex() .child( Headline::new("Welcome to Zed") .size(HeadlineSize::Small), ) .child( Label::new("The editor for what's next") .color(Color::Muted) .size(LabelSize::Small) .italic(), ), ), ) .child({ Button::new("finish_setup", "Finish Setup") .style(ButtonStyle::Filled) .size(ButtonSize::Medium) .width(rems_from_px(200.)) .key_binding(KeyBinding::for_action_in( &Finish, &self.focus_handle, cx, )) .on_click(|_, window, cx| { window.dispatch_action(Finish.boxed_clone(), cx); }) }), ) .child(Divider::horizontal().color(ui::DividerColor::BorderVariant)) .child(self.render_page(cx)), ) .track_scroll(&self.scroll_handle), ) }} impl EventEmitter<ItemEvent> for Onboarding {} impl Focusable for Onboarding { fn focus_handle(&self, _: &App) -> gpui::FocusHandle { self.focus_handle.clone() }} impl Item for Onboarding { type Event = ItemEvent; fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString { "Onboarding".into() } fn telemetry_event_text(&self) -> Option<&'static str> { Some("Onboarding Page Opened") } fn show_toolbar(&self) -> bool { false } fn can_split(&self) -> bool { true } fn clone_on_split( &self, _workspace_id: Option<WorkspaceId>, _: &mut Window, cx: &mut Context<Self>, ) -> Task<Option<Entity<Self>>> { Task::ready(Some(cx.new(|cx| Onboarding { workspace: self.workspace.clone(), user_store: self.user_store.clone(), scroll_handle: ScrollHandle::new(), focus_handle: cx.focus_handle(), _settings_subscription: cx.observe_global::<SettingsStore>(move |_, cx| cx.notify()), }))) } fn to_item_events(event: &Self::Event, f: &mut dyn FnMut(workspace::item::ItemEvent)) { f(*event) }} fn go_to_welcome_page(cx: &mut App) { with_active_or_new_workspace(cx, |workspace, window, cx| { let Some((onboarding_id, onboarding_idx)) = workspace .active_pane() .read(cx) .items() .enumerate() .find_map(|(idx, item)| { let _ = item.downcast::<Onboarding>()?; Some((item.item_id(), idx)) }) else { return; }; workspace.active_pane().update(cx, |pane, cx| { // Get the index here to get around the borrow checker let idx = pane.items().enumerate().find_map(|(idx, item)| { let _ = item.downcast::<WelcomePage>()?; Some(idx) }); if let Some(idx) = idx { pane.activate_item(idx, true, true, window, cx); } else { let item = Box::new( cx.new(|cx| WelcomePage::new(workspace.weak_handle(), false, window, cx)), ); pane.add_item(item, true, true, Some(onboarding_idx), window, cx); } pane.remove_item(onboarding_id, false, false, window, cx); }); });} pub async fn handle_import_vscode_settings( workspace: WeakEntity<Workspace>, 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 {}",Lines 1–500 of 716. Load more
use crate::multibuffer_hint::MultibufferHint; use client::{Client, UserStore, zed_urls}; use cloud_api_types::Plan; use db::kvp::KeyValueStore; use fs::Fs; use gpui::{ Action, AnyElement, App, AppContext, AsyncWindowContext, Context, Entity, EventEmitter, FocusHandle, Focusable, Global, IntoElement, KeyContext, Render, ScrollHandle, SharedString, Subscription, Task, WeakEntity, Window, actions, }; use notifications::status_toast::StatusToast; use project::agent_server_store::AllAgentServersSettings; use schemars::JsonSchema; use serde::Deserialize; use settings::{SettingsStore, VsCodeSettingsSource}; use std::sync::Arc; use ui::{ Divider, KeyBinding, ParentElement as _, StatefulInteractiveElement, Vector, VectorName, WithScrollbar as _, prelude::*, rems_from_px, }; pub use workspace::welcome::ShowWelcome; use workspace::welcome::WelcomePage; use workspace::{ AppState, Workspace, WorkspaceId, dock::DockPosition, item::{Item, ItemEvent}, notifications::NotifyResultExt as _, open_new, register_serializable_item, with_active_or_new_workspace, }; use zed_actions::OpenOnboarding; mod base_keymap_picker; mod basics_page; pub mod multibuffer_hint; mod theme_preview; /// 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"; actions!( onboarding, [ /// Finish the onboarding process. Finish, /// Sign in while in the onboarding flow. SignIn, /// Open the user account in zed.dev while in the onboarding flow. OpenAccount, /// Resets the welcome screen hints to their initial state. ResetHints ] ); pub fn init(cx: &mut App) { cx.observe_new(|workspace: &mut Workspace, _, _cx| { workspace .register_action(|_workspace, _: &ResetHints, _, cx| MultibufferHint::set_count(0, cx)); }) .detach(); cx.on_action(|_: &OpenOnboarding, cx| { with_active_or_new_workspace(cx, |workspace, window, cx| { workspace .with_local_workspace(window, cx, |workspace, window, cx| { let existing = workspace .active_pane() .read(cx) .items() .find_map(|item| item.downcast::<Onboarding>()); if let Some(existing) = existing { workspace.activate_item(&existing, true, true, window, cx); } else { let settings_page = Onboarding::new(workspace, cx); workspace.add_item_to_active_pane( Box::new(settings_page), None, true, window, cx, ) } }) .detach(); }); }); cx.on_action(|_: &ShowWelcome, cx| { with_active_or_new_workspace(cx, |workspace, window, cx| { workspace .with_local_workspace(window, cx, |workspace, window, cx| { let existing = workspace .active_pane() .read(cx) .items() .find_map(|item| item.downcast::<WelcomePage>()); if let Some(existing) = existing { workspace.activate_item(&existing, true, true, window, cx); } else { let settings_page = cx .new(|cx| WelcomePage::new(workspace.weak_handle(), false, window, cx)); workspace.add_item_to_active_pane( Box::new(settings_page), None, true, window, cx, ) } }) .detach(); }); }); 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; let workspace = cx.weak_entity(); window .spawn(cx, async move |cx: &mut AsyncWindowContext| { handle_import_vscode_settings( workspace, 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; let workspace = cx.weak_entity(); window .spawn(cx, async move |cx: &mut AsyncWindowContext| { handle_import_vscode_settings( workspace, VsCodeSettingsSource::Cursor, action.skip_prompt, fs, cx, ) .await }) .detach(); }); }) .detach(); base_keymap_picker::init(cx); register_serializable_item::<Onboarding>(cx); register_serializable_item::<WelcomePage>(cx); } pub fn show_onboarding_view(app_state: Arc<AppState>, cx: &mut App) -> Task<anyhow::Result<()>> { telemetry::event!("Onboarding Page Opened"); open_new( Default::default(), app_state, cx, |workspace, window, cx| { { workspace.toggle_dock(DockPosition::Left, window, cx); let onboarding_page = Onboarding::new(workspace, cx); workspace.add_item_to_center(Box::new(onboarding_page.clone()), window, cx); window.focus(&onboarding_page.focus_handle(cx), cx); cx.notify(); }; let kvp = KeyValueStore::global(cx); db::write_and_log(cx, move || async move { kvp.write_kvp(FIRST_OPEN.to_string(), "false".to_string()) .await }); }, ) } struct Onboarding { workspace: WeakEntity<Workspace>, focus_handle: FocusHandle, user_store: Entity<UserStore>, scroll_handle: ScrollHandle, _settings_subscription: Subscription, } impl Onboarding { fn new(workspace: &Workspace, cx: &mut App) -> Entity<Self> { let font_family_cache = theme::FontFamilyCache::global(cx); let installed_agents = cx .global::<SettingsStore>() .get::<AllAgentServersSettings>(None) .clone(); let client = Client::global(cx); let status = *client.status().borrow(); let plan = workspace.user_store().read(cx).plan(); let zed_agent_state = if status.is_signed_out() || matches!( status, client::Status::AuthenticationError | client::Status::ConnectionError ) { "signed_out" } else if status.is_signing_in() { "signing_in" } else { match plan { Some(Plan::ZedPro) => "pro", Some(Plan::ZedProTrial) => "trial", Some(Plan::ZedBusiness) => "business", Some(Plan::ZedVip) => "vip", Some(Plan::ZedStudent) => "student", Some(Plan::ZedFree) | None => "free", } }; let agents_installed = basics_page::FEATURED_AGENT_IDS .iter() .filter(|id| installed_agents.contains_key(**id)) .copied() .collect::<Vec<_>>(); telemetry::event!( "Welcome Agent Setup Viewed", zed_agent = zed_agent_state, agents_installed = agents_installed, ); cx.new(|cx| { cx.spawn(async move |this, cx| { font_family_cache.prefetch(cx).await; this.update(cx, |_, cx| { cx.notify(); }) }) .detach(); Self { workspace: workspace.weak_handle(), focus_handle: cx.focus_handle(), scroll_handle: ScrollHandle::new(), user_store: workspace.user_store().clone(), _settings_subscription: cx .observe_global::<SettingsStore>(move |_, cx| cx.notify()), } }) } fn on_finish(_: &Finish, _: &mut Window, cx: &mut App) { telemetry::event!("Finish Setup"); go_to_welcome_page(cx); } fn handle_sign_in(&mut self, _: &SignIn, window: &mut Window, cx: &mut Context<Self>) { let client = Client::global(cx); let workspace = self.workspace.clone(); window .spawn(cx, async move |mut cx| { client .sign_in_with_optional_connect(true, &cx) .await .notify_workspace_async_err(workspace, &mut cx); }) .detach(); } fn handle_open_account(_: &OpenAccount, _: &mut Window, cx: &mut App) { cx.open_url(&zed_urls::account_url(cx)) } fn render_page(&mut self, cx: &mut Context<Self>) -> AnyElement { crate::basics_page::render_basics_page(&self.user_store, cx).into_any_element() } } impl Render for Onboarding { fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { div() .image_cache(gpui::retain_all("onboarding-page")) .key_context({ let mut ctx = KeyContext::new_with_defaults(); ctx.add("Onboarding"); ctx.add("menu"); ctx }) .track_focus(&self.focus_handle) .size_full() .bg(cx.theme().colors().editor_background) .on_action(Self::on_finish) .on_action(cx.listener(Self::handle_sign_in)) .on_action(Self::handle_open_account) .on_action(cx.listener(|_, _: &menu::SelectNext, window, cx| { window.focus_next(cx); cx.notify(); })) .on_action(cx.listener(|_, _: &menu::SelectPrevious, window, cx| { window.focus_prev(cx); cx.notify(); })) .vertical_scrollbar_for(&self.scroll_handle, window, cx) .child( div() .id("page-content") .size_full() .overflow_y_scroll() .child( v_flex() .min_w_0() .max_w(rems_from_px(780.)) .w_full() .mx_auto() .p_12() .gap_6() .child( h_flex() .w_full() .gap_4() .justify_between() .child( h_flex() .gap_4() .child(Vector::square(VectorName::ZedLogo, rems(2.5))) .child( v_flex() .child( Headline::new("Welcome to Zed") .size(HeadlineSize::Small), ) .child( Label::new("The editor for what's next") .color(Color::Muted) .size(LabelSize::Small) .italic(), ), ), ) .child({ Button::new("finish_setup", "Finish Setup") .style(ButtonStyle::Filled) .size(ButtonSize::Medium) .width(rems_from_px(200.)) .key_binding(KeyBinding::for_action_in( &Finish, &self.focus_handle, cx, )) .on_click(|_, window, cx| { window.dispatch_action(Finish.boxed_clone(), cx); }) }), ) .child(Divider::horizontal().color(ui::DividerColor::BorderVariant)) .child(self.render_page(cx)), ) .track_scroll(&self.scroll_handle), ) } } impl EventEmitter<ItemEvent> for Onboarding {} impl Focusable for Onboarding { fn focus_handle(&self, _: &App) -> gpui::FocusHandle { self.focus_handle.clone() } } impl Item for Onboarding { type Event = ItemEvent; fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString { "Onboarding".into() } fn telemetry_event_text(&self) -> Option<&'static str> { Some("Onboarding Page Opened") } fn show_toolbar(&self) -> bool { false } fn can_split(&self) -> bool { true } fn clone_on_split( &self, _workspace_id: Option<WorkspaceId>, _: &mut Window, cx: &mut Context<Self>, ) -> Task<Option<Entity<Self>>> { Task::ready(Some(cx.new(|cx| Onboarding { workspace: self.workspace.clone(), user_store: self.user_store.clone(), scroll_handle: ScrollHandle::new(), focus_handle: cx.focus_handle(), _settings_subscription: cx.observe_global::<SettingsStore>(move |_, cx| cx.notify()), }))) } fn to_item_events(event: &Self::Event, f: &mut dyn FnMut(workspace::item::ItemEvent)) { f(*event) } } fn go_to_welcome_page(cx: &mut App) { with_active_or_new_workspace(cx, |workspace, window, cx| { let Some((onboarding_id, onboarding_idx)) = workspace .active_pane() .read(cx) .items() .enumerate() .find_map(|(idx, item)| { let _ = item.downcast::<Onboarding>()?; Some((item.item_id(), idx)) }) else { return; }; workspace.active_pane().update(cx, |pane, cx| { // Get the index here to get around the borrow checker let idx = pane.items().enumerate().find_map(|(idx, item)| { let _ = item.downcast::<WelcomePage>()?; Some(idx) }); if let Some(idx) = idx { pane.activate_item(idx, true, true, window, cx); } else { let item = Box::new( cx.new(|cx| WelcomePage::new(workspace.weak_handle(), false, window, cx)), ); pane.add_item(item, true, true, Some(onboarding_idx), window, cx); } pane.remove_item(onboarding_id, false, false, window, cx); }); }); } pub async fn handle_import_vscode_settings( workspace: WeakEntity<Workspace>, 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 {}",