diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index bfdb0a28d8423..db685a6f79c2f 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -153,51 +153,19 @@ pub fn initialize_workspace( .detach(); #[cfg(any(target_os = "linux", target_os = "freebsd"))] - if let Err(e) = fs::linux_watcher::global(|_| {}) { - let message = format!(db::indoc!{r#" - inotify_init returned {} - - This may be due to system-wide limits on inotify instances. For troubleshooting see: https://zed.dev/docs/linux - "#}, e); - let prompt = cx.prompt(PromptLevel::Critical, "Could not start inotify", Some(&message), - &["Troubleshoot and Quit"]); - cx.spawn(|_, mut cx| async move { - if prompt.await == Ok(0) { - cx.update(|cx| { - cx.open_url("https://zed.dev/docs/linux#could-not-start-inotify"); - cx.quit(); - }).ok(); - } - }).detach() - } + initialize_linux_file_watcher(cx); if let Some(specs) = cx.gpu_specs() { log::info!("Using GPU: {:?}", specs); - if specs.is_software_emulated && std::env::var("ZED_ALLOW_EMULATED_GPU").is_err() { - let message = format!(db::indoc!{r#" - Zed uses Vulkan for rendering and requires a compatible GPU. - - Currently you are using a software emulated GPU ({}) which - will result in awful performance. - - For troubleshooting see: https://zed.dev/docs/linux - Set ZED_ALLOW_EMULATED_GPU=1 env var to permanently override. - "#}, specs.device_name); - let prompt = cx.prompt(PromptLevel::Critical, "Unsupported GPU", Some(&message), - &["Skip", "Troubleshoot and Quit"]); - cx.spawn(|_, mut cx| async move { - if prompt.await == Ok(1) { - cx.update(|cx| { - cx.open_url("https://zed.dev/docs/linux#zed-fails-to-open-windows"); - cx.quit(); - }).ok(); - } - }).detach() - } + show_software_emulation_warning_if_needed(specs, cx); } let inline_completion_button = cx.new_view(|cx| { - inline_completion_button::InlineCompletionButton::new(workspace.weak_handle(), app_state.fs.clone(), cx) + inline_completion_button::InlineCompletionButton::new( + workspace.weak_handle(), + app_state.fs.clone(), + cx, + ) }); let diagnostic_summary = @@ -225,7 +193,6 @@ pub fn initialize_workspace( let handle = cx.view().downgrade(); cx.on_window_should_close(move |cx| { - handle .update(cx, |workspace, cx| { // We'll handle closing asynchronously @@ -235,390 +202,8 @@ pub fn initialize_workspace( .unwrap_or(true) }); - let release_channel = ReleaseChannel::global(cx); - let assistant2_feature_flag = cx.wait_for_flag::(); - let git_ui_feature_flag = cx.wait_for_flag::(); - - let prompt_builder = prompt_builder.clone(); - - cx.spawn(|workspace_handle, mut cx| async move { - let project_panel = ProjectPanel::load(workspace_handle.clone(), cx.clone()); - let outline_panel = OutlinePanel::load(workspace_handle.clone(), cx.clone()); - let terminal_panel = TerminalPanel::load(workspace_handle.clone(), cx.clone()); - let channels_panel = - collab_ui::collab_panel::CollabPanel::load(workspace_handle.clone(), cx.clone()); - let chat_panel = - collab_ui::chat_panel::ChatPanel::load(workspace_handle.clone(), cx.clone()); - let notification_panel = collab_ui::notification_panel::NotificationPanel::load( - workspace_handle.clone(), - cx.clone(), - ); - let assistant_panel = - assistant::AssistantPanel::load(workspace_handle.clone(), prompt_builder, cx.clone()); - - let ( - project_panel, - outline_panel, - terminal_panel, - channels_panel, - chat_panel, - notification_panel, - assistant_panel, - ) = futures::try_join!( - project_panel, - outline_panel, - terminal_panel, - channels_panel, - chat_panel, - notification_panel, - assistant_panel, - )?; - - workspace_handle.update(&mut cx, |workspace, cx| { - workspace.add_panel(project_panel, cx); - workspace.add_panel(outline_panel, cx); - workspace.add_panel(terminal_panel, cx); - workspace.add_panel(channels_panel, cx); - workspace.add_panel(chat_panel, cx); - workspace.add_panel(notification_panel, cx); - workspace.add_panel(assistant_panel, cx); - })?; - - let git_ui_enabled = git_ui_feature_flag.await; - let git_panel = if git_ui_enabled { - Some(git_ui::git_panel::GitPanel::load(workspace_handle.clone(), cx.clone()).await?) - } else { - None - }; - workspace_handle.update(&mut cx, |workspace, cx| { - if let Some(git_panel) = git_panel { - workspace.add_panel(git_panel, cx); - } - })?; - - let is_assistant2_enabled = - if cfg!(test) || release_channel != ReleaseChannel::Dev { - false - } else { - assistant2_feature_flag.await - }; - let assistant2_panel = if is_assistant2_enabled { - Some(assistant2::AssistantPanel::load(workspace_handle.clone(), cx.clone()).await?) - } else { - None - }; - workspace_handle.update(&mut cx, |workspace, cx| { - if let Some(assistant2_panel) = assistant2_panel { - workspace.add_panel(assistant2_panel, cx); - } - - if is_assistant2_enabled { - workspace.register_action(assistant2::InlineAssistant::inline_assist); - } else { - workspace.register_action(assistant::AssistantPanel::inline_assist); - } - }) - }) - .detach(); - - workspace - .register_action(about) - .register_action(|_, _: &Minimize, cx| { - cx.minimize_window(); - }) - .register_action(|_, _: &Zoom, cx| { - cx.zoom_window(); - }) - .register_action(|_, _: &ToggleFullScreen, cx| { - cx.toggle_fullscreen(); - }) - .register_action(|_, action: &OpenZedUrl, cx| { - OpenListener::global(cx).open_urls(vec![action.url.clone()]) - }) - .register_action(|_, action: &OpenBrowser, cx| cx.open_url(&action.url)) - .register_action(move |_, _: &zed_actions::IncreaseBufferFontSize, cx| { - theme::adjust_buffer_font_size(cx, |size| *size += px(1.0)) - }) - .register_action(|workspace, _: &workspace::Open, cx| { - workspace.client() - .telemetry() - .report_app_event("open project".to_string()); - let paths = workspace.prompt_for_open_path( - PathPromptOptions { - files: true, - directories: true, - multiple: true, - }, - DirectoryLister::Project(workspace.project().clone()), - cx, - ); - - cx.spawn(|this, mut cx| async move { - let Some(paths) = paths.await.log_err().flatten() else { - return; - }; - - if let Some(task) = this - .update(&mut cx, |this, cx| { - if this.project().read(cx).is_local() { - this.open_workspace_for_paths(false, paths, cx) - } else { - open_new_ssh_project_from_project(this, paths, cx) - } - }) - .log_err() - { - task.await.log_err(); - } - }) - .detach() - }) - .register_action(move |_, _: &zed_actions::DecreaseBufferFontSize, cx| { - theme::adjust_buffer_font_size(cx, |size| *size -= px(1.0)) - }) - .register_action(move |_, _: &zed_actions::ResetBufferFontSize, cx| { - theme::reset_buffer_font_size(cx) - }) - .register_action(move |_, _: &zed_actions::IncreaseUiFontSize, cx| { - theme::adjust_ui_font_size(cx, |size| *size += px(1.0)) - }) - .register_action(move |_, _: &zed_actions::DecreaseUiFontSize, cx| { - theme::adjust_ui_font_size(cx, |size| *size -= px(1.0)) - }) - .register_action(move |_, _: &zed_actions::ResetUiFontSize, cx| { - theme::reset_ui_font_size(cx) - }) - .register_action(move |_, _: &zed_actions::IncreaseBufferFontSize, cx| { - theme::adjust_buffer_font_size(cx, |size| *size += px(1.0)) - }) - .register_action(move |_, _: &zed_actions::DecreaseBufferFontSize, cx| { - theme::adjust_buffer_font_size(cx, |size| *size -= px(1.0)) - }) - .register_action(move |_, _: &zed_actions::ResetBufferFontSize, cx| { - theme::reset_buffer_font_size(cx) - }) - .register_action(|_, _: &install_cli::Install, cx| { - cx.spawn(|workspace, mut cx| async move { - if cfg!(any(target_os = "linux", target_os = "freebsd")) { - let prompt = cx.prompt( - PromptLevel::Warning, - "CLI should already be installed", - Some("If you installed Zed from our official release add ~/.local/bin to your PATH.\n\nIf you installed Zed from a different source like your package manager, then you may need to create an alias/symlink manually.\n\nDepending on your package manager, the CLI might be named zeditor, zedit, zed-editor or something else."), - &["Ok"], - ); - cx.background_executor().spawn(prompt).detach(); - return Ok(()); - } - let path = install_cli::install_cli(cx.deref()) - .await - .context("error creating CLI symlink")?; - - workspace.update(&mut cx, |workspace, cx| { - struct InstalledZedCli; - - workspace.show_toast( - Toast::new( - NotificationId::unique::(), - format!( - "Installed `zed` to {}. You can launch {} from your terminal.", - path.to_string_lossy(), - ReleaseChannel::global(cx).display_name() - ), - ), - cx, - ) - })?; - register_zed_scheme(&cx).await.log_err(); - Ok(()) - }) - .detach_and_prompt_err("Error installing zed cli", cx, |_, _| None); - }) - .register_action(|_, _: &install_cli::RegisterZedScheme, cx| { - cx.spawn(|workspace, mut cx| async move { - register_zed_scheme(&cx).await?; - workspace.update(&mut cx, |workspace, cx| { - struct RegisterZedScheme; - - workspace.show_toast( - Toast::new( - NotificationId::unique::(), - format!( - "zed:// links will now open in {}.", - ReleaseChannel::global(cx).display_name() - ), - ), - cx, - ) - })?; - Ok(()) - }) - .detach_and_prompt_err( - "Error registering zed:// scheme", - cx, - |_, _| None, - ); - }) - .register_action(|workspace, _: &OpenLog, cx| { - open_log_file(workspace, cx); - }) - .register_action(|workspace, _: &zed_actions::OpenLicenses, cx| { - open_bundled_file( - workspace, - asset_str::("licenses.md"), - "Open Source License Attribution", - "Markdown", - cx, - ); - }) - .register_action( - move |workspace: &mut Workspace, - _: &zed_actions::OpenTelemetryLog, - cx: &mut ViewContext| { - open_telemetry_log_file(workspace, cx); - }, - ) - .register_action( - move |_: &mut Workspace, - _: &zed_actions::OpenKeymap, - cx: &mut ViewContext| { - open_settings_file(paths::keymap_file(), || settings::initial_keymap_content().as_ref().into(), cx); - }, - ) - .register_action( - move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext| { - open_settings_file( - paths::settings_file(), - || settings::initial_user_settings_content().as_ref().into(), - cx, - ); - }, - ) - .register_action( - |_: &mut Workspace, _: &OpenAccountSettings, cx: &mut ViewContext| { - cx.open_url(&zed_urls::account_url(cx)); - }, - ) - .register_action( - move |_: &mut Workspace, _: &OpenTasks, cx: &mut ViewContext| { - open_settings_file( - paths::tasks_file(), - || settings::initial_tasks_content().as_ref().into(), - cx, - ); - }, - ) - .register_action(open_project_settings_file) - .register_action(open_project_tasks_file) - .register_action( - move |workspace: &mut Workspace, - _: &zed_actions::OpenDefaultKeymap, - cx: &mut ViewContext| { - open_bundled_file( - workspace, - settings::default_keymap(), - "Default Key Bindings", - "JSON", - cx, - ); - }, - ) - .register_action( - move |workspace: &mut Workspace, - _: &OpenDefaultSettings, - cx: &mut ViewContext| { - open_bundled_file( - workspace, - settings::default_settings(), - "Default Settings", - "JSON", - cx, - ); - }, - ) - .register_action( - |workspace: &mut Workspace, - _: &project_panel::ToggleFocus, - cx: &mut ViewContext| { - workspace.toggle_panel_focus::(cx); - }, - ) - .register_action( - |workspace: &mut Workspace, - _: &outline_panel::ToggleFocus, - cx: &mut ViewContext| { - workspace.toggle_panel_focus::(cx); - }, - ) - .register_action( - |workspace: &mut Workspace, - _: &collab_ui::collab_panel::ToggleFocus, - cx: &mut ViewContext| { - workspace.toggle_panel_focus::(cx); - }, - ) - .register_action( - |workspace: &mut Workspace, - _: &collab_ui::chat_panel::ToggleFocus, - cx: &mut ViewContext| { - workspace.toggle_panel_focus::(cx); - }, - ) - .register_action( - |workspace: &mut Workspace, - _: &collab_ui::notification_panel::ToggleFocus, - cx: &mut ViewContext| { - workspace - .toggle_panel_focus::(cx); - }, - ) - .register_action( - |workspace: &mut Workspace, - _: &terminal_panel::ToggleFocus, - cx: &mut ViewContext| { - workspace.toggle_panel_focus::(cx); - }, - ) - .register_action({ - let app_state = Arc::downgrade(&app_state); - move |_, _: &NewWindow, cx| { - if let Some(app_state) = app_state.upgrade() { - open_new(Default::default(), app_state, cx, |workspace, cx| { - Editor::new_file(workspace, &Default::default(), cx) - }) - .detach(); - } - } - }) - .register_action({ - let app_state = Arc::downgrade(&app_state); - move |_, _: &NewFile, cx| { - if let Some(app_state) = app_state.upgrade() { - open_new(Default::default(), app_state, cx, |workspace, cx| { - Editor::new_file(workspace, &Default::default(), cx) - }) - .detach(); - } - } - }); - if workspace.project().read(cx).is_via_ssh() { - workspace.register_action({ - move |workspace, _: &OpenServerSettings, cx| { - let open_server_settings = workspace.project().update(cx, |project, cx| { - project.open_server_settings(cx) - }); - - cx.spawn(|workspace, mut cx| async move { - let buffer = open_server_settings.await?; - - workspace.update(&mut cx, |workspace, cx| { - workspace.open_path(buffer.read(cx).project_path(cx).expect("Settings file must have a location"), None, true, cx) - })?.await?; - - anyhow::Ok(()) - }).detach_and_log_err(cx); - } - }); - } + initialize_panels(prompt_builder.clone(), cx); + register_actions(app_state.clone(), workspace, cx); workspace.focus_handle(cx).focus(cx); }) @@ -648,6 +233,441 @@ fn feature_gate_zed_pro_actions(cx: &mut AppContext) { .detach(); } +#[cfg(any(target_os = "linux", target_os = "freebsd"))] +fn initialize_linux_file_watcher(cx: &mut ViewContext) { + if let Err(e) = fs::linux_watcher::global(|_| {}) { + let message = format!( + db::indoc! {r#" + inotify_init returned {} + + This may be due to system-wide limits on inotify instances. For troubleshooting see: https://zed.dev/docs/linux + "#}, + e + ); + let prompt = cx.prompt( + PromptLevel::Critical, + "Could not start inotify", + Some(&message), + &["Troubleshoot and Quit"], + ); + cx.spawn(|_, mut cx| async move { + if prompt.await == Ok(0) { + cx.update(|cx| { + cx.open_url("https://zed.dev/docs/linux#could-not-start-inotify"); + cx.quit(); + }) + .ok(); + } + }) + .detach() + } +} + +fn show_software_emulation_warning_if_needed( + specs: gpui::GPUSpecs, + cx: &mut ViewContext, +) { + if specs.is_software_emulated && std::env::var("ZED_ALLOW_EMULATED_GPU").is_err() { + let message = format!( + db::indoc! {r#" + Zed uses Vulkan for rendering and requires a compatible GPU. + + Currently you are using a software emulated GPU ({}) which + will result in awful performance. + + For troubleshooting see: https://zed.dev/docs/linux + Set ZED_ALLOW_EMULATED_GPU=1 env var to permanently override. + "#}, + specs.device_name + ); + let prompt = cx.prompt( + PromptLevel::Critical, + "Unsupported GPU", + Some(&message), + &["Skip", "Troubleshoot and Quit"], + ); + cx.spawn(|_, mut cx| async move { + if prompt.await == Ok(1) { + cx.update(|cx| { + cx.open_url("https://zed.dev/docs/linux#zed-fails-to-open-windows"); + cx.quit(); + }) + .ok(); + } + }) + .detach() + } +} + +fn initialize_panels(prompt_builder: Arc, cx: &mut ViewContext) { + let release_channel = ReleaseChannel::global(cx); + let assistant2_feature_flag = cx.wait_for_flag::(); + let git_ui_feature_flag = cx.wait_for_flag::(); + + let prompt_builder = prompt_builder.clone(); + + cx.spawn(|workspace_handle, mut cx| async move { + let project_panel = ProjectPanel::load(workspace_handle.clone(), cx.clone()); + let outline_panel = OutlinePanel::load(workspace_handle.clone(), cx.clone()); + let terminal_panel = TerminalPanel::load(workspace_handle.clone(), cx.clone()); + let channels_panel = + collab_ui::collab_panel::CollabPanel::load(workspace_handle.clone(), cx.clone()); + let chat_panel = + collab_ui::chat_panel::ChatPanel::load(workspace_handle.clone(), cx.clone()); + let notification_panel = collab_ui::notification_panel::NotificationPanel::load( + workspace_handle.clone(), + cx.clone(), + ); + let assistant_panel = + assistant::AssistantPanel::load(workspace_handle.clone(), prompt_builder, cx.clone()); + + let ( + project_panel, + outline_panel, + terminal_panel, + channels_panel, + chat_panel, + notification_panel, + assistant_panel, + ) = futures::try_join!( + project_panel, + outline_panel, + terminal_panel, + channels_panel, + chat_panel, + notification_panel, + assistant_panel, + )?; + + workspace_handle.update(&mut cx, |workspace, cx| { + workspace.add_panel(project_panel, cx); + workspace.add_panel(outline_panel, cx); + workspace.add_panel(terminal_panel, cx); + workspace.add_panel(channels_panel, cx); + workspace.add_panel(chat_panel, cx); + workspace.add_panel(notification_panel, cx); + workspace.add_panel(assistant_panel, cx); + })?; + + let git_ui_enabled = git_ui_feature_flag.await; + let git_panel = if git_ui_enabled { + Some(git_ui::git_panel::GitPanel::load(workspace_handle.clone(), cx.clone()).await?) + } else { + None + }; + workspace_handle.update(&mut cx, |workspace, cx| { + if let Some(git_panel) = git_panel { + workspace.add_panel(git_panel, cx); + } + })?; + + let is_assistant2_enabled = if cfg!(test) || release_channel != ReleaseChannel::Dev { + false + } else { + assistant2_feature_flag.await + }; + let assistant2_panel = if is_assistant2_enabled { + Some(assistant2::AssistantPanel::load(workspace_handle.clone(), cx.clone()).await?) + } else { + None + }; + workspace_handle.update(&mut cx, |workspace, cx| { + if let Some(assistant2_panel) = assistant2_panel { + workspace.add_panel(assistant2_panel, cx); + } + + if is_assistant2_enabled { + workspace.register_action(assistant2::InlineAssistant::inline_assist); + } else { + workspace.register_action(assistant::AssistantPanel::inline_assist); + } + }) + }) + .detach(); +} + +fn register_actions( + app_state: Arc, + workspace: &mut Workspace, + cx: &mut ViewContext, +) { + workspace + .register_action(about) + .register_action(|_, _: &Minimize, cx| { + cx.minimize_window(); + }) + .register_action(|_, _: &Zoom, cx| { + cx.zoom_window(); + }) + .register_action(|_, _: &ToggleFullScreen, cx| { + cx.toggle_fullscreen(); + }) + .register_action(|_, action: &OpenZedUrl, cx| { + OpenListener::global(cx).open_urls(vec![action.url.clone()]) + }) + .register_action(|_, action: &OpenBrowser, cx| cx.open_url(&action.url)) + .register_action(move |_, _: &zed_actions::IncreaseBufferFontSize, cx| { + theme::adjust_buffer_font_size(cx, |size| *size += px(1.0)) + }) + .register_action(|workspace, _: &workspace::Open, cx| { + workspace + .client() + .telemetry() + .report_app_event("open project".to_string()); + let paths = workspace.prompt_for_open_path( + PathPromptOptions { + files: true, + directories: true, + multiple: true, + }, + DirectoryLister::Project(workspace.project().clone()), + cx, + ); + + cx.spawn(|this, mut cx| async move { + let Some(paths) = paths.await.log_err().flatten() else { + return; + }; + + if let Some(task) = this + .update(&mut cx, |this, cx| { + if this.project().read(cx).is_local() { + this.open_workspace_for_paths(false, paths, cx) + } else { + open_new_ssh_project_from_project(this, paths, cx) + } + }) + .log_err() + { + task.await.log_err(); + } + }) + .detach() + }) + .register_action(move |_, _: &zed_actions::DecreaseBufferFontSize, cx| { + theme::adjust_buffer_font_size(cx, |size| *size -= px(1.0)) + }) + .register_action(move |_, _: &zed_actions::ResetBufferFontSize, cx| { + theme::reset_buffer_font_size(cx) + }) + .register_action(move |_, _: &zed_actions::IncreaseUiFontSize, cx| { + theme::adjust_ui_font_size(cx, |size| *size += px(1.0)) + }) + .register_action(move |_, _: &zed_actions::DecreaseUiFontSize, cx| { + theme::adjust_ui_font_size(cx, |size| *size -= px(1.0)) + }) + .register_action(move |_, _: &zed_actions::ResetUiFontSize, cx| { + theme::reset_ui_font_size(cx) + }) + .register_action(move |_, _: &zed_actions::IncreaseBufferFontSize, cx| { + theme::adjust_buffer_font_size(cx, |size| *size += px(1.0)) + }) + .register_action(move |_, _: &zed_actions::DecreaseBufferFontSize, cx| { + theme::adjust_buffer_font_size(cx, |size| *size -= px(1.0)) + }) + .register_action(move |_, _: &zed_actions::ResetBufferFontSize, cx| { + theme::reset_buffer_font_size(cx) + }) + .register_action(install_cli) + .register_action(|_, _: &install_cli::RegisterZedScheme, cx| { + cx.spawn(|workspace, mut cx| async move { + register_zed_scheme(&cx).await?; + workspace.update(&mut cx, |workspace, cx| { + struct RegisterZedScheme; + + workspace.show_toast( + Toast::new( + NotificationId::unique::(), + format!( + "zed:// links will now open in {}.", + ReleaseChannel::global(cx).display_name() + ), + ), + cx, + ) + })?; + Ok(()) + }) + .detach_and_prompt_err("Error registering zed:// scheme", cx, |_, _| None); + }) + .register_action(|workspace, _: &OpenLog, cx| { + open_log_file(workspace, cx); + }) + .register_action(|workspace, _: &zed_actions::OpenLicenses, cx| { + open_bundled_file( + workspace, + asset_str::("licenses.md"), + "Open Source License Attribution", + "Markdown", + cx, + ); + }) + .register_action( + move |workspace: &mut Workspace, + _: &zed_actions::OpenTelemetryLog, + cx: &mut ViewContext| { + open_telemetry_log_file(workspace, cx); + }, + ) + .register_action( + move |_: &mut Workspace, + _: &zed_actions::OpenKeymap, + cx: &mut ViewContext| { + open_settings_file( + paths::keymap_file(), + || settings::initial_keymap_content().as_ref().into(), + cx, + ); + }, + ) + .register_action( + move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext| { + open_settings_file( + paths::settings_file(), + || settings::initial_user_settings_content().as_ref().into(), + cx, + ); + }, + ) + .register_action( + |_: &mut Workspace, _: &OpenAccountSettings, cx: &mut ViewContext| { + cx.open_url(&zed_urls::account_url(cx)); + }, + ) + .register_action( + move |_: &mut Workspace, _: &OpenTasks, cx: &mut ViewContext| { + open_settings_file( + paths::tasks_file(), + || settings::initial_tasks_content().as_ref().into(), + cx, + ); + }, + ) + .register_action(open_project_settings_file) + .register_action(open_project_tasks_file) + .register_action( + move |workspace: &mut Workspace, + _: &zed_actions::OpenDefaultKeymap, + cx: &mut ViewContext| { + open_bundled_file( + workspace, + settings::default_keymap(), + "Default Key Bindings", + "JSON", + cx, + ); + }, + ) + .register_action( + move |workspace: &mut Workspace, + _: &OpenDefaultSettings, + cx: &mut ViewContext| { + open_bundled_file( + workspace, + settings::default_settings(), + "Default Settings", + "JSON", + cx, + ); + }, + ) + .register_action( + |workspace: &mut Workspace, + _: &project_panel::ToggleFocus, + cx: &mut ViewContext| { + workspace.toggle_panel_focus::(cx); + }, + ) + .register_action( + |workspace: &mut Workspace, + _: &outline_panel::ToggleFocus, + cx: &mut ViewContext| { + workspace.toggle_panel_focus::(cx); + }, + ) + .register_action( + |workspace: &mut Workspace, + _: &collab_ui::collab_panel::ToggleFocus, + cx: &mut ViewContext| { + workspace.toggle_panel_focus::(cx); + }, + ) + .register_action( + |workspace: &mut Workspace, + _: &collab_ui::chat_panel::ToggleFocus, + cx: &mut ViewContext| { + workspace.toggle_panel_focus::(cx); + }, + ) + .register_action( + |workspace: &mut Workspace, + _: &collab_ui::notification_panel::ToggleFocus, + cx: &mut ViewContext| { + workspace + .toggle_panel_focus::(cx); + }, + ) + .register_action( + |workspace: &mut Workspace, + _: &terminal_panel::ToggleFocus, + cx: &mut ViewContext| { + workspace.toggle_panel_focus::(cx); + }, + ) + .register_action({ + let app_state = Arc::downgrade(&app_state); + move |_, _: &NewWindow, cx| { + if let Some(app_state) = app_state.upgrade() { + open_new(Default::default(), app_state, cx, |workspace, cx| { + Editor::new_file(workspace, &Default::default(), cx) + }) + .detach(); + } + } + }) + .register_action({ + let app_state = Arc::downgrade(&app_state); + move |_, _: &NewFile, cx| { + if let Some(app_state) = app_state.upgrade() { + open_new(Default::default(), app_state, cx, |workspace, cx| { + Editor::new_file(workspace, &Default::default(), cx) + }) + .detach(); + } + } + }); + if workspace.project().read(cx).is_via_ssh() { + workspace.register_action({ + move |workspace, _: &OpenServerSettings, cx| { + let open_server_settings = workspace + .project() + .update(cx, |project, cx| project.open_server_settings(cx)); + + cx.spawn(|workspace, mut cx| async move { + let buffer = open_server_settings.await?; + + workspace + .update(&mut cx, |workspace, cx| { + workspace.open_path( + buffer + .read(cx) + .project_path(cx) + .expect("Settings file must have a location"), + None, + true, + cx, + ) + })? + .await?; + + anyhow::Ok(()) + }) + .detach_and_log_err(cx); + } + }); + } +} + fn initialize_pane(workspace: &Workspace, pane: &View, cx: &mut ViewContext) { pane.update(cx, |pane, cx| { pane.toolbar().update(cx, |toolbar, cx| { @@ -694,6 +714,45 @@ fn test_panic(_: &TestPanic, _: &mut AppContext) { panic!("Ran the TestPanic action") } +fn install_cli(_: &mut Workspace, _: &install_cli::Install, cx: &mut ViewContext) { + const LINUX_PROMPT_DETAIL: &str = "If you installed Zed from our official release add ~/.local/bin to your PATH.\n\nIf you installed Zed from a different source like your package manager, then you may need to create an alias/symlink manually.\n\nDepending on your package manager, the CLI might be named zeditor, zedit, zed-editor or something else."; + + cx.spawn(|workspace, mut cx| async move { + if cfg!(any(target_os = "linux", target_os = "freebsd")) { + let prompt = cx.prompt( + PromptLevel::Warning, + "CLI should already be installed", + Some(LINUX_PROMPT_DETAIL), + &["Ok"], + ); + cx.background_executor().spawn(prompt).detach(); + return Ok(()); + } + let path = install_cli::install_cli(cx.deref()) + .await + .context("error creating CLI symlink")?; + + workspace.update(&mut cx, |workspace, cx| { + struct InstalledZedCli; + + workspace.show_toast( + Toast::new( + NotificationId::unique::(), + format!( + "Installed `zed` to {}. You can launch {} from your terminal.", + path.to_string_lossy(), + ReleaseChannel::global(cx).display_name() + ), + ), + cx, + ) + })?; + register_zed_scheme(&cx).await.log_err(); + Ok(()) + }) + .detach_and_prompt_err("Error installing zed cli", cx, |_, _| None); +} + fn quit(_: &Quit, cx: &mut AppContext) { let should_confirm = WorkspaceSettings::get_global(cx).confirm_quit; cx.spawn(|mut cx| async move {