1431 lines · 44.5 KB · Rust
RawDownload
use crate::{    pane::{self, Pane},    persistence::model::ItemId,    searchable::SearchableItemHandle,    workspace_settings::{AutosaveSetting, WorkspaceSettings},    DelayedDebouncedEditAction, FollowableViewRegistry, ItemNavHistory, SerializableItemRegistry,    ToolbarItemLocation, ViewId, Workspace, WorkspaceId,};use anyhow::Result;use client::{    proto::{self, PeerId},    Client,};use futures::{channel::mpsc, StreamExt};use gpui::{    AnyElement, AnyView, AppContext, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,    Font, HighlightStyle, Model, Pixels, Point, SharedString, Task, View, ViewContext, WeakView,    WindowContext,};use project::{Project, ProjectEntryId, ProjectPath};use schemars::JsonSchema;use serde::{Deserialize, Serialize};use settings::{Settings, SettingsLocation, SettingsSources};use smallvec::SmallVec;use std::{    any::{Any, TypeId},    cell::RefCell,    ops::Range,    rc::Rc,    sync::Arc,    time::Duration,};use theme::Theme;use ui::{Color, Element as _, Icon, IntoElement, Label, LabelCommon};use util::ResultExt; pub const LEADER_UPDATE_THROTTLE: Duration = Duration::from_millis(200); #[derive(Deserialize)]pub struct ItemSettings {    pub git_status: bool,    pub close_position: ClosePosition,    pub activate_on_close: ActivateOnClose,    pub file_icons: bool,    pub show_diagnostics: ShowDiagnostics,    pub always_show_close_button: bool,} #[derive(Deserialize)]pub struct PreviewTabsSettings {    pub enabled: bool,    pub enable_preview_from_file_finder: bool,    pub enable_preview_from_code_navigation: bool,} #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]#[serde(rename_all = "lowercase")]pub enum ClosePosition {    Left,    #[default]    Right,} #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]#[serde(rename_all = "snake_case")]pub enum ShowDiagnostics {    #[default]    Off,    Errors,    All,} #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]#[serde(rename_all = "snake_case")]pub enum ActivateOnClose {    #[default]    History,    Neighbour,    LeftNeighbour,} #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]pub struct ItemSettingsContent {    /// Whether to show the Git file status on a tab item.    ///    /// Default: false    git_status: Option<bool>,    /// Position of the close button in a tab.    ///    /// Default: right    close_position: Option<ClosePosition>,    /// Whether to show the file icon for a tab.    ///    /// Default: false    file_icons: Option<bool>,    /// What to do after closing the current tab.    ///    /// Default: history    pub activate_on_close: Option<ActivateOnClose>,    /// Which files containing diagnostic errors/warnings to mark in the tabs.    /// This setting can take the following three values:    ///    /// Default: off    show_diagnostics: Option<ShowDiagnostics>,    /// Whether to always show the close button on tabs.    ///    /// Default: false    always_show_close_button: Option<bool>,} #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]pub struct PreviewTabsSettingsContent {    /// Whether to show opened editors as preview tabs.    /// Preview tabs do not stay open, are reused until explicitly set to be kept open opened (via double-click or editing) and show file names in italic.    ///    /// Default: true    enabled: Option<bool>,    /// Whether to open tabs in preview mode when selected from the file finder.    ///    /// Default: false    enable_preview_from_file_finder: Option<bool>,    /// Whether a preview tab gets replaced when code navigation is used to navigate away from the tab.    ///    /// Default: false    enable_preview_from_code_navigation: Option<bool>,} impl Settings for ItemSettings {    const KEY: Option<&'static str> = Some("tabs");     type FileContent = ItemSettingsContent;     fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {        sources.json_merge()    }} impl Settings for PreviewTabsSettings {    const KEY: Option<&'static str> = Some("preview_tabs");     type FileContent = PreviewTabsSettingsContent;     fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {        sources.json_merge()    }} #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]pub enum ItemEvent {    CloseItem,    UpdateTab,    UpdateBreadcrumbs,    Edit,} // TODO: Combine this with existing HighlightedText struct?pub struct BreadcrumbText {    pub text: String,    pub highlights: Option<Vec<(Range<usize>, HighlightStyle)>>,    pub font: Option<Font>,} #[derive(Debug, Clone, Copy)]pub struct TabContentParams {    pub detail: Option<usize>,    pub selected: bool,    pub preview: bool,} impl TabContentParams {    /// Returns the text color to be used for the tab content.    pub fn text_color(&self) -> Color {        if self.selected {            Color::Default        } else {            Color::Muted        }    }} pub enum TabTooltipContent {    Text(SharedString),    Custom(Box<dyn Fn(&mut WindowContext) -> AnyView>),} pub trait Item: FocusableView + EventEmitter<Self::Event> {    type Event;     /// Returns the tab contents.    ///    /// By default this returns a [`Label`] that displays that text from    /// `tab_content_text`.    fn tab_content(&self, params: TabContentParams, cx: &WindowContext) -> AnyElement {        let Some(text) = self.tab_content_text(cx) else {            return gpui::Empty.into_any();        };         Label::new(text)            .color(params.text_color())            .into_any_element()    }     /// Returns the textual contents of the tab.    ///    /// Use this if you don't need to customize the tab contents.    fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {        None    }     fn tab_icon(&self, _cx: &WindowContext) -> Option<Icon> {        None    }     /// Returns the tab tooltip text.    ///    /// Use this if you don't need to customize the tab tooltip content.    fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> {        None    }     /// Returns the tab tooltip content.    ///    /// By default this returns a Tooltip text from    /// `tab_tooltip_text`.    fn tab_tooltip_content(&self, cx: &AppContext) -> Option<TabTooltipContent> {        self.tab_tooltip_text(cx).map(TabTooltipContent::Text)    }     fn tab_description(&self, _: usize, _: &AppContext) -> Option<SharedString> {        None    }     fn to_item_events(_event: &Self::Event, _f: impl FnMut(ItemEvent)) {}     fn deactivated(&mut self, _: &mut ViewContext<Self>) {}    fn discarded(&self, _project: Model<Project>, _cx: &mut ViewContext<Self>) {}    fn workspace_deactivated(&mut self, _: &mut ViewContext<Self>) {}    fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool {        false    }     fn telemetry_event_text(&self) -> Option<&'static str> {        None    }     /// (model id, Item)    fn for_each_project_item(        &self,        _: &AppContext,        _: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),    ) {    }    fn is_singleton(&self, _cx: &AppContext) -> bool {        false    }    fn set_nav_history(&mut self, _: ItemNavHistory, _: &mut ViewContext<Self>) {}    fn clone_on_split(        &self,        _workspace_id: Option<WorkspaceId>,        _: &mut ViewContext<Self>,    ) -> Option<View<Self>>    where        Self: Sized,    {        None    }    fn is_dirty(&self, _: &AppContext) -> bool {        false    }    fn has_deleted_file(&self, _: &AppContext) -> bool {        false    }    fn has_conflict(&self, _: &AppContext) -> bool {        false    }    fn can_save(&self, _cx: &AppContext) -> bool {        false    }    fn save(        &mut self,        _format: bool,        _project: Model<Project>,        _cx: &mut ViewContext<Self>,    ) -> Task<Result<()>> {        unimplemented!("save() must be implemented if can_save() returns true")    }    fn save_as(        &mut self,        _project: Model<Project>,        _path: ProjectPath,        _cx: &mut ViewContext<Self>,    ) -> Task<Result<()>> {        unimplemented!("save_as() must be implemented if can_save() returns true")    }    fn reload(        &mut self,        _project: Model<Project>,        _cx: &mut ViewContext<Self>,    ) -> Task<Result<()>> {        unimplemented!("reload() must be implemented if can_save() returns true")    }     fn act_as_type<'a>(        &'a self,        type_id: TypeId,        self_handle: &'a View<Self>,        _: &'a AppContext,    ) -> Option<AnyView> {        if TypeId::of::<Self>() == type_id {            Some(self_handle.clone().into())        } else {            None        }    }     fn as_searchable(&self, _: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {        None    }     fn breadcrumb_location(&self, _: &AppContext) -> ToolbarItemLocation {        ToolbarItemLocation::Hidden    }     fn breadcrumbs(&self, _theme: &Theme, _cx: &AppContext) -> Option<Vec<BreadcrumbText>> {        None    }     fn added_to_workspace(&mut self, _workspace: &mut Workspace, _cx: &mut ViewContext<Self>) {}     fn show_toolbar(&self) -> bool {        true    }     fn pixel_position_of_cursor(&self, _: &AppContext) -> Option<Point<Pixels>> {        None    }     fn preserve_preview(&self, _cx: &AppContext) -> bool {        false    }     fn include_in_nav_history() -> bool {        true    }} pub trait SerializableItem: Item {    fn serialized_item_kind() -> &'static str;     fn cleanup(        workspace_id: WorkspaceId,        alive_items: Vec<ItemId>,        cx: &mut WindowContext,    ) -> Task<Result<()>>;     fn deserialize(        _project: Model<Project>,        _workspace: WeakView<Workspace>,        _workspace_id: WorkspaceId,        _item_id: ItemId,        _cx: &mut WindowContext,    ) -> Task<Result<View<Self>>>;     fn serialize(        &mut self,        workspace: &mut Workspace,        item_id: ItemId,        closing: bool,        cx: &mut ViewContext<Self>,    ) -> Option<Task<Result<()>>>;     fn should_serialize(&self, event: &Self::Event) -> bool;} pub trait SerializableItemHandle: ItemHandle {    fn serialized_item_kind(&self) -> &'static str;    fn serialize(        &self,        workspace: &mut Workspace,        closing: bool,        cx: &mut WindowContext,    ) -> Option<Task<Result<()>>>;    fn should_serialize(&self, event: &dyn Any, cx: &AppContext) -> bool;} impl<T> SerializableItemHandle for View<T>where    T: SerializableItem,{    fn serialized_item_kind(&self) -> &'static str {        T::serialized_item_kind()    }     fn serialize(        &self,        workspace: &mut Workspace,        closing: bool,        cx: &mut WindowContext,    ) -> Option<Task<Result<()>>> {        self.update(cx, |this, cx| {            this.serialize(workspace, cx.entity_id().as_u64(), closing, cx)        })    }     fn should_serialize(&self, event: &dyn Any, cx: &AppContext) -> bool {        event            .downcast_ref::<T::Event>()            .map_or(false, |event| self.read(cx).should_serialize(event))    }} pub trait ItemHandle: 'static + Send {    fn subscribe_to_item_events(        &self,        cx: &mut WindowContext,        handler: Box<dyn Fn(ItemEvent, &mut WindowContext)>,    ) -> gpui::Subscription;    fn focus_handle(&self, cx: &WindowContext) -> FocusHandle;    fn tab_description(&self, detail: usize, cx: &AppContext) -> Option<SharedString>;    fn tab_content(&self, params: TabContentParams, cx: &WindowContext) -> AnyElement;    fn tab_icon(&self, cx: &WindowContext) -> Option<Icon>;    fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString>;    fn tab_tooltip_content(&self, cx: &AppContext) -> Option<TabTooltipContent>;    fn telemetry_event_text(&self, cx: &WindowContext) -> Option<&'static str>;    fn dragged_tab_content(&self, params: TabContentParams, cx: &WindowContext) -> AnyElement;    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;    fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]>;    fn project_paths(&self, cx: &AppContext) -> SmallVec<[ProjectPath; 3]>;    fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[EntityId; 3]>;    fn for_each_project_item(        &self,        _: &AppContext,        _: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),    );    fn is_singleton(&self, cx: &AppContext) -> bool;    fn boxed_clone(&self) -> Box<dyn ItemHandle>;    fn clone_on_split(        &self,        workspace_id: Option<WorkspaceId>,        cx: &mut WindowContext,    ) -> Option<Box<dyn ItemHandle>>;    fn added_to_pane(        &self,        workspace: &mut Workspace,        pane: View<Pane>,        cx: &mut ViewContext<Workspace>,    );    fn deactivated(&self, cx: &mut WindowContext);    fn discarded(&self, project: Model<Project>, cx: &mut WindowContext);    fn workspace_deactivated(&self, cx: &mut WindowContext);    fn navigate(&self, data: Box<dyn Any>, cx: &mut WindowContext) -> bool;    fn item_id(&self) -> EntityId;    fn to_any(&self) -> AnyView;    fn is_dirty(&self, cx: &AppContext) -> bool;    fn has_deleted_file(&self, cx: &AppContext) -> bool;    fn has_conflict(&self, cx: &AppContext) -> bool;    fn can_save(&self, cx: &AppContext) -> bool;    fn save(        &self,        format: bool,        project: Model<Project>,        cx: &mut WindowContext,    ) -> Task<Result<()>>;    fn save_as(        &self,        project: Model<Project>,        path: ProjectPath,        cx: &mut WindowContext,    ) -> Task<Result<()>>;    fn reload(&self, project: Model<Project>, cx: &mut WindowContext) -> Task<Result<()>>;    fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option<AnyView>;    fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>>;    fn to_serializable_item_handle(        &self,        cx: &AppContext,    ) -> Option<Box<dyn SerializableItemHandle>>;    fn on_release(        &self,        cx: &mut AppContext,        callback: Box<dyn FnOnce(&mut AppContext) + Send>,    ) -> gpui::Subscription;    fn to_searchable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>>;    fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation;    fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>>;    fn show_toolbar(&self, cx: &AppContext) -> bool;    fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Point<Pixels>>;    fn downgrade_item(&self) -> Box<dyn WeakItemHandle>;    fn workspace_settings<'a>(&self, cx: &'a AppContext) -> &'a WorkspaceSettings;    fn preserve_preview(&self, cx: &AppContext) -> bool;    fn include_in_nav_history(&self) -> bool;} pub trait WeakItemHandle: Send + Sync {    fn id(&self) -> EntityId;    fn boxed_clone(&self) -> Box<dyn WeakItemHandle>;    fn upgrade(&self) -> Option<Box<dyn ItemHandle>>;} impl dyn ItemHandle {    pub fn downcast<V: 'static>(&self) -> Option<View<V>> {

Lines 1–500 of 1431.