pub mod dock;pub mod history_manager;pub mod item;mod modal_layer;pub mod notifications;pub mod pane;pub mod pane_group;mod persistence;pub mod searchable;pub mod shared_screen;mod status_bar;pub mod tasks;mod theme_preview;mod toast_layer;mod toolbar;mod workspace_settings; pub use toast_layer::{RunAction, ToastAction, ToastLayer, ToastView}; use anyhow::{Context as _, Result, anyhow};use call::{ActiveCall, call_settings::CallSettings};use client::{ ChannelId, Client, ErrorExt, Status, TypedEnvelope, UserStore, proto::{self, ErrorCode, PanelId, PeerId},};use collections::{HashMap, HashSet, hash_map};pub use dock::Panel;use dock::{Dock, DockPosition, PanelButtons, PanelHandle, RESIZE_HANDLE_SIZE};use futures::{ Future, FutureExt, StreamExt, channel::{ mpsc::{self, UnboundedReceiver, UnboundedSender}, oneshot, }, future::try_join_all,};use gpui::{ Action, AnyEntity, AnyView, AnyWeakView, App, AsyncApp, AsyncWindowContext, Bounds, Context, CursorStyle, Decorations, DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, Focusable, Global, HitboxBehavior, Hsla, KeyContext, Keystroke, ManagedView, MouseButton, PathPromptOptions, Point, PromptLevel, Render, ResizeEdge, Size, Stateful, Subscription, Task, Tiling, WeakEntity, WindowBounds, WindowHandle, WindowId, WindowOptions, action_as, actions, canvas, impl_action_as, impl_actions, point, relative, size, transparent_black,};pub use history_manager::*;pub use item::{ FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, PreviewTabsSettings, ProjectItem, SerializableItem, SerializableItemHandle, WeakItemHandle,};use itertools::Itertools;use language::{Buffer, LanguageRegistry, Rope};pub use modal_layer::*;use node_runtime::NodeRuntime;use notifications::{ DetachAndPromptErr, Notifications, dismiss_app_notification, simple_message_notification::MessageNotification,};pub use pane::*;pub use pane_group::*;use persistence::{ DB, SerializedWindowBounds, model::{SerializedSshProject, SerializedWorkspace},};pub use persistence::{ DB as WORKSPACE_DB, WorkspaceDb, delete_unloaded_items, model::{ItemId, LocalPaths, SerializedWorkspaceLocation},};use postage::stream::Stream;use project::{ DirectoryLister, Project, ProjectEntryId, ProjectPath, ResolvedPath, Worktree, WorktreeId, debugger::{breakpoint_store::BreakpointStoreEvent, session::ThreadStatus},};use remote::{SshClientDelegate, SshConnectionOptions, ssh_session::ConnectionIdentifier};use schemars::JsonSchema;use serde::Deserialize;use session::AppSession;use settings::Settings;use shared_screen::SharedScreen;use sqlez::{ bindable::{Bind, Column, StaticColumnCount}, statement::Statement,};use status_bar::StatusBar;pub use status_bar::StatusItemView;use std::{ any::TypeId, borrow::Cow, cell::RefCell, cmp, collections::hash_map::DefaultHasher, env, hash::{Hash, Hasher}, path::{Path, PathBuf}, process::ExitStatus, rc::Rc, sync::{Arc, LazyLock, Weak, atomic::AtomicUsize}, time::Duration,};use task::{DebugScenario, SpawnInTerminal, TaskContext};use theme::{ActiveTheme, SystemAppearance, ThemeSettings};pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};pub use ui;use ui::{Window, prelude::*};use util::{ResultExt, TryFutureExt, paths::SanitizedPath, serde::default_true};use uuid::Uuid;pub use workspace_settings::{ AutosaveSetting, BottomDockLayout, RestoreOnStartupBehavior, TabBarSettings, WorkspaceSettings,};use zed_actions::{Spawn, feedback::FileBugReport}; use crate::notifications::NotificationId;use crate::persistence::{ SerializedAxis, model::{DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup},}; pub const SERIALIZATION_THROTTLE_TIME: Duration = Duration::from_millis(200); static ZED_WINDOW_SIZE: LazyLock<Option<Size<Pixels>>> = LazyLock::new(|| { env::var("ZED_WINDOW_SIZE") .ok() .as_deref() .and_then(parse_pixel_size_env_var)}); static ZED_WINDOW_POSITION: LazyLock<Option<Point<Pixels>>> = LazyLock::new(|| { env::var("ZED_WINDOW_POSITION") .ok() .as_deref() .and_then(parse_pixel_position_env_var)}); pub trait TerminalProvider { fn spawn( &self, task: SpawnInTerminal, window: &mut Window, cx: &mut App, ) -> Task<Option<Result<ExitStatus>>>;} pub trait DebuggerProvider { // `active_buffer` is used to resolve build task's name against language-specific tasks. fn start_session( &self, definition: DebugScenario, task_context: TaskContext, active_buffer: Option<Entity<Buffer>>, window: &mut Window, cx: &mut App, ); fn spawn_task_or_modal( &self, workspace: &mut Workspace, action: &Spawn, window: &mut Window, cx: &mut Context<Workspace>, ); fn task_scheduled(&self, cx: &mut App); fn debug_scenario_scheduled(&self, cx: &mut App); fn debug_scenario_scheduled_last(&self, cx: &App) -> bool; fn active_thread_state(&self, cx: &App) -> Option<ThreadStatus>;} actions!( workspace, [ ActivateNextPane, ActivatePreviousPane, ActivateNextWindow, ActivatePreviousWindow, AddFolderToProject, ClearAllNotifications, CloseActiveDock, CloseAllDocks, CloseWindow, Feedback, FollowNextCollaborator, MoveFocusedPanelToNextPosition, NewCenterTerminal, NewFile, NewFileSplitVertical, NewFileSplitHorizontal, NewSearch, NewTerminal, NewWindow, Open, OpenFiles, OpenInTerminal, OpenComponentPreview, ReloadActiveItem, SaveAs, SaveWithoutFormat, ShutdownDebugAdapters, SuppressNotification, ToggleBottomDock, ToggleCenteredLayout, ToggleLeftDock, ToggleRightDock, ToggleZoom, Unfollow, Welcome, RestoreBanner, ToggleExpandItem, ]); #[derive(Clone, PartialEq)]pub struct OpenPaths { pub paths: Vec<PathBuf>,} #[derive(Clone, Deserialize, PartialEq, JsonSchema)]pub struct ActivatePane(pub usize); #[derive(Clone, Deserialize, PartialEq, JsonSchema)]#[serde(deny_unknown_fields)]pub struct MoveItemToPane { pub destination: usize, #[serde(default = "default_true")] pub focus: bool,} #[derive(Clone, Deserialize, PartialEq, JsonSchema)]#[serde(deny_unknown_fields)]pub struct MoveItemToPaneInDirection { pub direction: SplitDirection, #[serde(default = "default_true")] pub focus: bool,} #[derive(Clone, PartialEq, Debug, Deserialize, JsonSchema)]#[serde(deny_unknown_fields)]pub struct SaveAll { pub save_intent: Option<SaveIntent>,} #[derive(Clone, PartialEq, Debug, Deserialize, JsonSchema)]#[serde(deny_unknown_fields)]pub struct Save { pub save_intent: Option<SaveIntent>,} #[derive(Clone, PartialEq, Debug, Deserialize, Default, JsonSchema)]#[serde(deny_unknown_fields)]pub struct CloseAllItemsAndPanes { pub save_intent: Option<SaveIntent>,} #[derive(Clone, PartialEq, Debug, Deserialize, Default, JsonSchema)]#[serde(deny_unknown_fields)]pub struct CloseInactiveTabsAndPanes { pub save_intent: Option<SaveIntent>,} #[derive(Clone, Deserialize, PartialEq, JsonSchema)]pub struct SendKeystrokes(pub String); #[derive(Clone, Deserialize, PartialEq, Default, JsonSchema)]#[serde(deny_unknown_fields)]pub struct Reload { pub binary_path: Option<PathBuf>,} action_as!(project_symbols, ToggleProjectSymbols as Toggle); #[derive(Default, PartialEq, Eq, Clone, Deserialize, JsonSchema)]pub struct ToggleFileFinder { #[serde(default)] pub separate_history: bool,} impl_action_as!(file_finder, ToggleFileFinder as Toggle); impl_actions!( workspace, [ ActivatePane, CloseAllItemsAndPanes, CloseInactiveTabsAndPanes, MoveItemToPane, MoveItemToPaneInDirection, OpenTerminal, Reload, Save, SaveAll, SendKeystrokes, ]); actions!( workspace, [ ActivatePaneLeft, ActivatePaneRight, ActivatePaneUp, ActivatePaneDown, SwapPaneLeft, SwapPaneRight, SwapPaneUp, SwapPaneDown, ]); #[derive(PartialEq, Eq, Debug)]pub enum CloseIntent { /// Quit the program entirely. Quit, /// Close a window. CloseWindow, /// Replace the workspace in an existing window. ReplaceWindow,} #[derive(Clone)]pub struct Toast { id: NotificationId, msg: Cow<'static, str>, autohide: bool, on_click: Option<(Cow<'static, str>, Arc<dyn Fn(&mut Window, &mut App)>)>,} impl Toast { pub fn new<I: Into<Cow<'static, str>>>(id: NotificationId, msg: I) -> Self { Toast { id, msg: msg.into(), on_click: None, autohide: false, } } pub fn on_click<F, M>(mut self, message: M, on_click: F) -> Self where M: Into<Cow<'static, str>>, F: Fn(&mut Window, &mut App) + 'static, { self.on_click = Some((message.into(), Arc::new(on_click))); self } pub fn autohide(mut self) -> Self { self.autohide = true; self }} impl PartialEq for Toast { fn eq(&self, other: &Self) -> bool { self.id == other.id && self.msg == other.msg && self.on_click.is_some() == other.on_click.is_some() }} #[derive(Debug, Default, Clone, Deserialize, PartialEq, JsonSchema)]#[serde(deny_unknown_fields)]pub struct OpenTerminal { pub working_directory: PathBuf,} #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]pub struct WorkspaceId(i64); impl StaticColumnCount for WorkspaceId {}impl Bind for WorkspaceId { fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> { self.0.bind(statement, start_index) }}impl Column for WorkspaceId { fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> { i64::column(statement, start_index) .map(|(i, next_index)| (Self(i), next_index)) .with_context(|| format!("Failed to read WorkspaceId at index {start_index}")) }}impl From<WorkspaceId> for i64 { fn from(val: WorkspaceId) -> Self { val.0 }} pub fn init_settings(cx: &mut App) { WorkspaceSettings::register(cx); ItemSettings::register(cx); PreviewTabsSettings::register(cx); TabBarSettings::register(cx);} fn prompt_and_open_paths(app_state: Arc<AppState>, options: PathPromptOptions, cx: &mut App) { let paths = cx.prompt_for_paths(options); cx.spawn( async move |cx| match paths.await.anyhow().and_then(|res| res) { Ok(Some(paths)) => { cx.update(|cx| { open_paths(&paths, app_state, OpenOptions::default(), cx).detach_and_log_err(cx) }) .ok(); } Ok(None) => {} Err(err) => { util::log_err(&err); cx.update(|cx| { if let Some(workspace_window) = cx .active_window() .and_then(|window| window.downcast::<Workspace>()) { workspace_window .update(cx, |workspace, _, cx| { workspace.show_portal_error(err.to_string(), cx); }) .ok(); } }) .ok(); } }, ) .detach();} pub fn init(app_state: Arc<AppState>, cx: &mut App) { init_settings(cx); component::init(); theme_preview::init(cx); toast_layer::init(cx); history_manager::init(cx); cx.on_action(Workspace::close_global); cx.on_action(reload); cx.on_action({ let app_state = Arc::downgrade(&app_state); move |_: &Open, cx: &mut App| { if let Some(app_state) = app_state.upgrade() { prompt_and_open_paths( app_state, PathPromptOptions { files: true, directories: true, multiple: true, }, cx, ); } } }); cx.on_action({ let app_state = Arc::downgrade(&app_state); move |_: &OpenFiles, cx: &mut App| { let directories = cx.can_select_mixed_files_and_dirs(); if let Some(app_state) = app_state.upgrade() { prompt_and_open_paths( app_state, PathPromptOptions { files: true, directories, multiple: true, }, cx, ); } } });} type BuildProjectItemFn = fn(AnyEntity, Entity<Project>, Option<&Pane>, &mut Window, &mut App) -> Box<dyn ItemHandle>; type BuildProjectItemForPathFn = fn( &Entity<Project>, &ProjectPath, &mut Window, &mut App, ) -> Option<Task<Result<(Option<ProjectEntryId>, WorkspaceItemBuilder)>>>; #[derive(Clone, Default)]struct ProjectItemRegistry { build_project_item_fns_by_type: HashMap<TypeId, BuildProjectItemFn>, build_project_item_for_path_fns: Vec<BuildProjectItemForPathFn>,} impl ProjectItemRegistry { fn register<T: ProjectItem>(&mut self) { self.build_project_item_fns_by_type.insert( TypeId::of::<T::Item>(), |item, project, pane, window, cx| { let item = item.downcast().unwrap(); Box::new(cx.new(|cx| T::for_project_item(project, pane, item, window, cx))) as Box<dyn ItemHandle> }, ); self.build_project_item_for_path_fns .push(|project, project_path, window, cx| { let project_item =Lines 1–500 of 10228. Load more
pub mod dock; pub mod history_manager; pub mod item; mod modal_layer; pub mod notifications; pub mod pane; pub mod pane_group; mod persistence; pub mod searchable; pub mod shared_screen; mod status_bar; pub mod tasks; mod theme_preview; mod toast_layer; mod toolbar; mod workspace_settings; pub use toast_layer::{RunAction, ToastAction, ToastLayer, ToastView}; use anyhow::{Context as _, Result, anyhow}; use call::{ActiveCall, call_settings::CallSettings}; use client::{ ChannelId, Client, ErrorExt, Status, TypedEnvelope, UserStore, proto::{self, ErrorCode, PanelId, PeerId}, }; use collections::{HashMap, HashSet, hash_map}; pub use dock::Panel; use dock::{Dock, DockPosition, PanelButtons, PanelHandle, RESIZE_HANDLE_SIZE}; use futures::{ Future, FutureExt, StreamExt, channel::{ mpsc::{self, UnboundedReceiver, UnboundedSender}, oneshot, }, future::try_join_all, }; use gpui::{ Action, AnyEntity, AnyView, AnyWeakView, App, AsyncApp, AsyncWindowContext, Bounds, Context, CursorStyle, Decorations, DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, Focusable, Global, HitboxBehavior, Hsla, KeyContext, Keystroke, ManagedView, MouseButton, PathPromptOptions, Point, PromptLevel, Render, ResizeEdge, Size, Stateful, Subscription, Task, Tiling, WeakEntity, WindowBounds, WindowHandle, WindowId, WindowOptions, action_as, actions, canvas, impl_action_as, impl_actions, point, relative, size, transparent_black, }; pub use history_manager::*; pub use item::{ FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, PreviewTabsSettings, ProjectItem, SerializableItem, SerializableItemHandle, WeakItemHandle, }; use itertools::Itertools; use language::{Buffer, LanguageRegistry, Rope}; pub use modal_layer::*; use node_runtime::NodeRuntime; use notifications::{ DetachAndPromptErr, Notifications, dismiss_app_notification, simple_message_notification::MessageNotification, }; pub use pane::*; pub use pane_group::*; use persistence::{ DB, SerializedWindowBounds, model::{SerializedSshProject, SerializedWorkspace}, }; pub use persistence::{ DB as WORKSPACE_DB, WorkspaceDb, delete_unloaded_items, model::{ItemId, LocalPaths, SerializedWorkspaceLocation}, }; use postage::stream::Stream; use project::{ DirectoryLister, Project, ProjectEntryId, ProjectPath, ResolvedPath, Worktree, WorktreeId, debugger::{breakpoint_store::BreakpointStoreEvent, session::ThreadStatus}, }; use remote::{SshClientDelegate, SshConnectionOptions, ssh_session::ConnectionIdentifier}; use schemars::JsonSchema; use serde::Deserialize; use session::AppSession; use settings::Settings; use shared_screen::SharedScreen; use sqlez::{ bindable::{Bind, Column, StaticColumnCount}, statement::Statement, }; use status_bar::StatusBar; pub use status_bar::StatusItemView; use std::{ any::TypeId, borrow::Cow, cell::RefCell, cmp, collections::hash_map::DefaultHasher, env, hash::{Hash, Hasher}, path::{Path, PathBuf}, process::ExitStatus, rc::Rc, sync::{Arc, LazyLock, Weak, atomic::AtomicUsize}, time::Duration, }; use task::{DebugScenario, SpawnInTerminal, TaskContext}; use theme::{ActiveTheme, SystemAppearance, ThemeSettings}; pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView}; pub use ui; use ui::{Window, prelude::*}; use util::{ResultExt, TryFutureExt, paths::SanitizedPath, serde::default_true}; use uuid::Uuid; pub use workspace_settings::{ AutosaveSetting, BottomDockLayout, RestoreOnStartupBehavior, TabBarSettings, WorkspaceSettings, }; use zed_actions::{Spawn, feedback::FileBugReport}; use crate::notifications::NotificationId; use crate::persistence::{ SerializedAxis, model::{DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup}, }; pub const SERIALIZATION_THROTTLE_TIME: Duration = Duration::from_millis(200); static ZED_WINDOW_SIZE: LazyLock<Option<Size<Pixels>>> = LazyLock::new(|| { env::var("ZED_WINDOW_SIZE") .ok() .as_deref() .and_then(parse_pixel_size_env_var) }); static ZED_WINDOW_POSITION: LazyLock<Option<Point<Pixels>>> = LazyLock::new(|| { env::var("ZED_WINDOW_POSITION") .ok() .as_deref() .and_then(parse_pixel_position_env_var) }); pub trait TerminalProvider { fn spawn( &self, task: SpawnInTerminal, window: &mut Window, cx: &mut App, ) -> Task<Option<Result<ExitStatus>>>; } pub trait DebuggerProvider { // `active_buffer` is used to resolve build task's name against language-specific tasks. fn start_session( &self, definition: DebugScenario, task_context: TaskContext, active_buffer: Option<Entity<Buffer>>, window: &mut Window, cx: &mut App, ); fn spawn_task_or_modal( &self, workspace: &mut Workspace, action: &Spawn, window: &mut Window, cx: &mut Context<Workspace>, ); fn task_scheduled(&self, cx: &mut App); fn debug_scenario_scheduled(&self, cx: &mut App); fn debug_scenario_scheduled_last(&self, cx: &App) -> bool; fn active_thread_state(&self, cx: &App) -> Option<ThreadStatus>; } actions!( workspace, [ ActivateNextPane, ActivatePreviousPane, ActivateNextWindow, ActivatePreviousWindow, AddFolderToProject, ClearAllNotifications, CloseActiveDock, CloseAllDocks, CloseWindow, Feedback, FollowNextCollaborator, MoveFocusedPanelToNextPosition, NewCenterTerminal, NewFile, NewFileSplitVertical, NewFileSplitHorizontal, NewSearch, NewTerminal, NewWindow, Open, OpenFiles, OpenInTerminal, OpenComponentPreview, ReloadActiveItem, SaveAs, SaveWithoutFormat, ShutdownDebugAdapters, SuppressNotification, ToggleBottomDock, ToggleCenteredLayout, ToggleLeftDock, ToggleRightDock, ToggleZoom, Unfollow, Welcome, RestoreBanner, ToggleExpandItem, ] ); #[derive(Clone, PartialEq)] pub struct OpenPaths { pub paths: Vec<PathBuf>, } #[derive(Clone, Deserialize, PartialEq, JsonSchema)] pub struct ActivatePane(pub usize); #[derive(Clone, Deserialize, PartialEq, JsonSchema)] #[serde(deny_unknown_fields)] pub struct MoveItemToPane { pub destination: usize, #[serde(default = "default_true")] pub focus: bool, } #[derive(Clone, Deserialize, PartialEq, JsonSchema)] #[serde(deny_unknown_fields)] pub struct MoveItemToPaneInDirection { pub direction: SplitDirection, #[serde(default = "default_true")] pub focus: bool, } #[derive(Clone, PartialEq, Debug, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] pub struct SaveAll { pub save_intent: Option<SaveIntent>, } #[derive(Clone, PartialEq, Debug, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] pub struct Save { pub save_intent: Option<SaveIntent>, } #[derive(Clone, PartialEq, Debug, Deserialize, Default, JsonSchema)] #[serde(deny_unknown_fields)] pub struct CloseAllItemsAndPanes { pub save_intent: Option<SaveIntent>, } #[derive(Clone, PartialEq, Debug, Deserialize, Default, JsonSchema)] #[serde(deny_unknown_fields)] pub struct CloseInactiveTabsAndPanes { pub save_intent: Option<SaveIntent>, } #[derive(Clone, Deserialize, PartialEq, JsonSchema)] pub struct SendKeystrokes(pub String); #[derive(Clone, Deserialize, PartialEq, Default, JsonSchema)] #[serde(deny_unknown_fields)] pub struct Reload { pub binary_path: Option<PathBuf>, } action_as!(project_symbols, ToggleProjectSymbols as Toggle); #[derive(Default, PartialEq, Eq, Clone, Deserialize, JsonSchema)] pub struct ToggleFileFinder { #[serde(default)] pub separate_history: bool, } impl_action_as!(file_finder, ToggleFileFinder as Toggle); impl_actions!( workspace, [ ActivatePane, CloseAllItemsAndPanes, CloseInactiveTabsAndPanes, MoveItemToPane, MoveItemToPaneInDirection, OpenTerminal, Reload, Save, SaveAll, SendKeystrokes, ] ); actions!( workspace, [ ActivatePaneLeft, ActivatePaneRight, ActivatePaneUp, ActivatePaneDown, SwapPaneLeft, SwapPaneRight, SwapPaneUp, SwapPaneDown, ] ); #[derive(PartialEq, Eq, Debug)] pub enum CloseIntent { /// Quit the program entirely. Quit, /// Close a window. CloseWindow, /// Replace the workspace in an existing window. ReplaceWindow, } #[derive(Clone)] pub struct Toast { id: NotificationId, msg: Cow<'static, str>, autohide: bool, on_click: Option<(Cow<'static, str>, Arc<dyn Fn(&mut Window, &mut App)>)>, } impl Toast { pub fn new<I: Into<Cow<'static, str>>>(id: NotificationId, msg: I) -> Self { Toast { id, msg: msg.into(), on_click: None, autohide: false, } } pub fn on_click<F, M>(mut self, message: M, on_click: F) -> Self where M: Into<Cow<'static, str>>, F: Fn(&mut Window, &mut App) + 'static, { self.on_click = Some((message.into(), Arc::new(on_click))); self } pub fn autohide(mut self) -> Self { self.autohide = true; self } } impl PartialEq for Toast { fn eq(&self, other: &Self) -> bool { self.id == other.id && self.msg == other.msg && self.on_click.is_some() == other.on_click.is_some() } } #[derive(Debug, Default, Clone, Deserialize, PartialEq, JsonSchema)] #[serde(deny_unknown_fields)] pub struct OpenTerminal { pub working_directory: PathBuf, } #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct WorkspaceId(i64); impl StaticColumnCount for WorkspaceId {} impl Bind for WorkspaceId { fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> { self.0.bind(statement, start_index) } } impl Column for WorkspaceId { fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> { i64::column(statement, start_index) .map(|(i, next_index)| (Self(i), next_index)) .with_context(|| format!("Failed to read WorkspaceId at index {start_index}")) } } impl From<WorkspaceId> for i64 { fn from(val: WorkspaceId) -> Self { val.0 } } pub fn init_settings(cx: &mut App) { WorkspaceSettings::register(cx); ItemSettings::register(cx); PreviewTabsSettings::register(cx); TabBarSettings::register(cx); } fn prompt_and_open_paths(app_state: Arc<AppState>, options: PathPromptOptions, cx: &mut App) { let paths = cx.prompt_for_paths(options); cx.spawn( async move |cx| match paths.await.anyhow().and_then(|res| res) { Ok(Some(paths)) => { cx.update(|cx| { open_paths(&paths, app_state, OpenOptions::default(), cx).detach_and_log_err(cx) }) .ok(); } Ok(None) => {} Err(err) => { util::log_err(&err); cx.update(|cx| { if let Some(workspace_window) = cx .active_window() .and_then(|window| window.downcast::<Workspace>()) { workspace_window .update(cx, |workspace, _, cx| { workspace.show_portal_error(err.to_string(), cx); }) .ok(); } }) .ok(); } }, ) .detach(); } pub fn init(app_state: Arc<AppState>, cx: &mut App) { init_settings(cx); component::init(); theme_preview::init(cx); toast_layer::init(cx); history_manager::init(cx); cx.on_action(Workspace::close_global); cx.on_action(reload); cx.on_action({ let app_state = Arc::downgrade(&app_state); move |_: &Open, cx: &mut App| { if let Some(app_state) = app_state.upgrade() { prompt_and_open_paths( app_state, PathPromptOptions { files: true, directories: true, multiple: true, }, cx, ); } } }); cx.on_action({ let app_state = Arc::downgrade(&app_state); move |_: &OpenFiles, cx: &mut App| { let directories = cx.can_select_mixed_files_and_dirs(); if let Some(app_state) = app_state.upgrade() { prompt_and_open_paths( app_state, PathPromptOptions { files: true, directories, multiple: true, }, cx, ); } } }); } type BuildProjectItemFn = fn(AnyEntity, Entity<Project>, Option<&Pane>, &mut Window, &mut App) -> Box<dyn ItemHandle>; type BuildProjectItemForPathFn = fn( &Entity<Project>, &ProjectPath, &mut Window, &mut App, ) -> Option<Task<Result<(Option<ProjectEntryId>, WorkspaceItemBuilder)>>>; #[derive(Clone, Default)] struct ProjectItemRegistry { build_project_item_fns_by_type: HashMap<TypeId, BuildProjectItemFn>, build_project_item_for_path_fns: Vec<BuildProjectItemForPathFn>, } impl ProjectItemRegistry { fn register<T: ProjectItem>(&mut self) { self.build_project_item_fns_by_type.insert( TypeId::of::<T::Item>(), |item, project, pane, window, cx| { let item = item.downcast().unwrap(); Box::new(cx.new(|cx| T::for_project_item(project, pane, item, window, cx))) as Box<dyn ItemHandle> }, ); self.build_project_item_for_path_fns .push(|project, project_path, window, cx| { let project_item =