9287 lines · 336.0 KB · Rust
RawDownload
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; use dap::DapRegistry;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};use derive_more::{Deref, DerefMut};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, AnyView, AnyWeakView, App, AsyncApp, AsyncWindowContext, Bounds, Context, CursorStyle,    Decorations, DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, Focusable, Global,    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::{LanguageRegistry, Rope};pub use modal_layer::*;use node_runtime::NodeRuntime;use notifications::{    DetachAndPromptErr, Notifications, 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,    model::{ItemId, LocalPaths, SerializedWorkspaceLocation},};use postage::stream::Stream;use project::{    DirectoryLister, Project, ProjectEntryId, ProjectPath, ResolvedPath, Worktree, WorktreeId,    debugger::breakpoint_store::BreakpointStoreEvent,};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},    rc::Rc,    sync::{Arc, LazyLock, Weak, atomic::AtomicUsize},    time::Duration,};use task::{DebugTaskDefinition, SpawnInTerminal, TaskId};use theme::{ActiveTheme, SystemAppearance, ThemeSettings};pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};pub use ui;use ui::prelude::*;use util::{ResultExt, TryFutureExt, paths::SanitizedPath, serde::default_true};use uuid::Uuid;pub use workspace_settings::{    AutosaveSetting, BottomDockLayout, RestoreOnStartupBehavior, TabBarSettings, WorkspaceSettings,}; 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)}); actions!(    workspace,    [        ActivateNextPane,        ActivatePreviousPane,        ActivateNextWindow,        ActivatePreviousWindow,        AddFolderToProject,        ClearAllNotifications,        CloseAllDocks,        CloseWindow,        Feedback,        FollowNextCollaborator,        MoveFocusedPanelToNextPosition,        NewCenterTerminal,        NewFile,        NewFileSplitVertical,        NewFileSplitHorizontal,        NewSearch,        NewTerminal,        NewWindow,        Open,        OpenFiles,        OpenInTerminal,        OpenComponentPreview,        ReloadActiveItem,        SaveAs,        SaveWithoutFormat,        ShutdownDebugAdapters,        ToggleBottomDock,        ToggleCenteredLayout,        ToggleLeftDock,        ToggleRightDock,        ToggleZoom,        Unfollow,        Welcome,        RestoreBanner,    ]); #[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,                );            }        }    });} #[derive(Clone, Default, Deref, DerefMut)]struct ProjectItemOpeners(Vec<ProjectItemOpener>); type ProjectItemOpener = fn(    &Entity<Project>,    &ProjectPath,    &mut Window,    &mut App,)    -> Option<Task<Result<(Option<ProjectEntryId>, WorkspaceItemBuilder)>>>; type WorkspaceItemBuilder =    Box<dyn FnOnce(&mut Pane, &mut Window, &mut Context<Pane>) -> Box<dyn ItemHandle>>; impl Global for ProjectItemOpeners {} /// Registers a [ProjectItem] for the app. When opening a file, all the registered/// items will get a chance to open the file, starting from the project item that/// was added last.pub fn register_project_item<I: ProjectItem>(cx: &mut App) {    let builders = cx.default_global::<ProjectItemOpeners>();    builders.push(|project, project_path, window, cx| {        let project_item = <I::Item as project::ProjectItem>::try_open(project, project_path, cx)?;        let project = project.clone();        Some(window.spawn(cx, async move |cx| {            let project_item = project_item.await?;            let project_entry_id: Option<ProjectEntryId> =                project_item.read_with(cx, project::ProjectItem::entry_id)?;            let build_workspace_item = Box::new(                |pane: &mut Pane, window: &mut Window, cx: &mut Context<Pane>| {                    Box::new(                        cx.new(|cx| I::for_project_item(project, pane, project_item, window, cx)),                    ) as Box<dyn ItemHandle>                },            ) as Box<_>;            Ok((project_entry_id, build_workspace_item))        }))    });} #[derive(Default)]pub struct FollowableViewRegistry(HashMap<TypeId, FollowableViewDescriptor>); struct FollowableViewDescriptor {    from_state_proto: fn(        Entity<Workspace>,        ViewId,        &mut Option<proto::view::Variant>,        &mut Window,        &mut App,    ) -> Option<Task<Result<Box<dyn FollowableItemHandle>>>>,    to_followable_view: fn(&AnyView) -> Box<dyn FollowableItemHandle>,} impl Global for FollowableViewRegistry {} impl FollowableViewRegistry {    pub fn register<I: FollowableItem>(cx: &mut App) {        cx.default_global::<Self>().0.insert(            TypeId::of::<I>(),            FollowableViewDescriptor {                from_state_proto: |workspace, id, state, window, cx| {                    I::from_state_proto(workspace, id, state, window, cx).map(|task| {                        cx.foreground_executor()                            .spawn(async move { Ok(Box::new(task.await?) as Box<_>) })                    })                },                to_followable_view: |view| Box::new(view.clone().downcast::<I>().unwrap()),            },

Lines 1–500 of 9287.