1706 lines · 53.4 KB · Rust
RawDownload
use crate::{    CollaboratorId, DelayedDebouncedEditAction, FollowableViewRegistry, ItemNavHistory,    SerializableItemRegistry, ToolbarItemLocation, ViewId, Workspace, WorkspaceId,    pane::{self, Pane},    persistence::model::ItemId,    searchable::SearchableItemHandle,    workspace_settings::{AutosaveSetting, WorkspaceSettings},};use anyhow::Result;use client::{Client, proto};use futures::{StreamExt, channel::mpsc};use gpui::{    Action, AnyElement, AnyView, App, Context, Entity, EntityId, EventEmitter, FocusHandle,    Focusable, Font, HighlightStyle, Pixels, Point, Render, SharedString, Task, WeakEntity, Window,};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, 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 show_close_button: ShowCloseButton,} #[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(Clone, Default, Serialize, Deserialize, JsonSchema)]#[serde(rename_all = "lowercase")]pub enum ShowCloseButton {    Always,    #[default]    Hover,    Hidden,} #[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    show_close_button: Option<ShowCloseButton>,} #[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 App) -> Result<Self> {        sources.json_merge()    }     fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {        if let Some(b) = vscode.read_bool("workbench.editor.tabActionCloseVisibility") {            current.show_close_button = Some(if b {                ShowCloseButton::Always            } else {                ShowCloseButton::Hidden            })        }        vscode.enum_setting(            "workbench.editor.tabActionLocation",            &mut current.close_position,            |s| match s {                "right" => Some(ClosePosition::Right),                "left" => Some(ClosePosition::Left),                _ => None,            },        );        if let Some(b) = vscode.read_bool("workbench.editor.focusRecentEditorAfterClose") {            current.activate_on_close = Some(if b {                ActivateOnClose::History            } else {                ActivateOnClose::LeftNeighbour            })        }         vscode.bool_setting("workbench.editor.showIcons", &mut current.file_icons);        vscode.bool_setting("git.decorations.enabled", &mut current.git_status);    }} impl Settings for PreviewTabsSettings {    const KEY: Option<&'static str> = Some("preview_tabs");     type FileContent = PreviewTabsSettingsContent;     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {        sources.json_merge()    }     fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {        vscode.bool_setting("workbench.editor.enablePreview", &mut current.enabled);        vscode.bool_setting(            "workbench.editor.enablePreviewFromCodeNavigation",            &mut current.enable_preview_from_code_navigation,        );        vscode.bool_setting(            "workbench.editor.enablePreviewFromQuickOpen",            &mut current.enable_preview_from_file_finder,        );    }} #[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(Clone, Copy, Default, Debug)]pub struct TabContentParams {    pub detail: Option<usize>,    pub selected: bool,    pub preview: bool,    /// Tab content should be deemphasized when active pane does not have focus.    pub deemphasized: bool,} impl TabContentParams {    /// Returns the text color to be used for the tab content.    pub fn text_color(&self) -> Color {        if self.deemphasized {            if self.selected {                Color::Muted            } else {                Color::Hidden            }        } else if self.selected {            Color::Default        } else {            Color::Muted        }    }} pub enum TabTooltipContent {    Text(SharedString),    Custom(Box<dyn Fn(&mut Window, &mut App) -> AnyView>),} pub trait Item: Focusable + EventEmitter<Self::Event> + Render + Sized {    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, _window: &Window, cx: &App) -> AnyElement {        let text = self.tab_content_text(params.detail.unwrap_or_default(), cx);         Label::new(text)            .color(params.text_color())            .into_any_element()    }     /// Returns the textual contents of the tab.    fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString;     fn tab_icon(&self, _window: &Window, _cx: &App) -> 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, _: &App) -> 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: &App) -> Option<TabTooltipContent> {        self.tab_tooltip_text(cx).map(TabTooltipContent::Text)    }     fn to_item_events(_event: &Self::Event, _f: impl FnMut(ItemEvent)) {}     fn deactivated(&mut self, _window: &mut Window, _: &mut Context<Self>) {}    fn discarded(&self, _project: Entity<Project>, _window: &mut Window, _cx: &mut Context<Self>) {}    fn workspace_deactivated(&mut self, _window: &mut Window, _: &mut Context<Self>) {}    fn navigate(&mut self, _: Box<dyn Any>, _window: &mut Window, _: &mut Context<Self>) -> bool {        false    }     fn telemetry_event_text(&self) -> Option<&'static str> {        None    }     /// (model id, Item)    fn for_each_project_item(        &self,        _: &App,        _: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),    ) {    }    fn is_singleton(&self, _cx: &App) -> bool {        false    }    fn set_nav_history(&mut self, _: ItemNavHistory, _window: &mut Window, _: &mut Context<Self>) {}    fn clone_on_split(        &self,        _workspace_id: Option<WorkspaceId>,        _window: &mut Window,        _: &mut Context<Self>,    ) -> Option<Entity<Self>>    where        Self: Sized,    {        None    }    fn is_dirty(&self, _: &App) -> bool {        false    }    fn has_deleted_file(&self, _: &App) -> bool {        false    }    fn has_conflict(&self, _: &App) -> bool {        false    }    fn can_save(&self, _cx: &App) -> bool {        false    }    fn can_save_as(&self, _: &App) -> bool {        false    }    fn save(        &mut self,        _format: bool,        _project: Entity<Project>,        _window: &mut Window,        _cx: &mut Context<Self>,    ) -> Task<Result<()>> {        unimplemented!("save() must be implemented if can_save() returns true")    }    fn save_as(        &mut self,        _project: Entity<Project>,        _path: ProjectPath,        _window: &mut Window,        _cx: &mut Context<Self>,    ) -> Task<Result<()>> {        unimplemented!("save_as() must be implemented if can_save() returns true")    }    fn reload(        &mut self,        _project: Entity<Project>,        _window: &mut Window,        _cx: &mut Context<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 Entity<Self>,        _: &'a App,    ) -> Option<AnyView> {        if TypeId::of::<Self>() == type_id {            Some(self_handle.clone().into())        } else {            None        }    }     fn as_searchable(&self, _: &Entity<Self>) -> Option<Box<dyn SearchableItemHandle>> {        None    }     fn breadcrumb_location(&self, _: &App) -> ToolbarItemLocation {        ToolbarItemLocation::Hidden    }     fn breadcrumbs(&self, _theme: &Theme, _cx: &App) -> Option<Vec<BreadcrumbText>> {        None    }     fn added_to_workspace(        &mut self,        _workspace: &mut Workspace,        _window: &mut Window,        _cx: &mut Context<Self>,    ) {    }     fn show_toolbar(&self) -> bool {        true    }     fn pixel_position_of_cursor(&self, _: &App) -> Option<Point<Pixels>> {        None    }     fn preserve_preview(&self, _cx: &App) -> 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>,        window: &mut Window,        cx: &mut App,    ) -> Task<Result<()>>;     fn deserialize(        _project: Entity<Project>,        _workspace: WeakEntity<Workspace>,        _workspace_id: WorkspaceId,        _item_id: ItemId,        _window: &mut Window,        _cx: &mut App,    ) -> Task<Result<Entity<Self>>>;     fn serialize(        &mut self,        workspace: &mut Workspace,        item_id: ItemId,        closing: bool,        window: &mut Window,        cx: &mut Context<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,        window: &mut Window,        cx: &mut App,    ) -> Option<Task<Result<()>>>;    fn should_serialize(&self, event: &dyn Any, cx: &App) -> bool;} impl<T> SerializableItemHandle for Entity<T>where    T: SerializableItem,{    fn serialized_item_kind(&self) -> &'static str {        T::serialized_item_kind()    }     fn serialize(        &self,        workspace: &mut Workspace,        closing: bool,        window: &mut Window,        cx: &mut App,    ) -> Option<Task<Result<()>>> {        self.update(cx, |this, cx| {            this.serialize(workspace, cx.entity_id().as_u64(), closing, window, cx)        })    }     fn should_serialize(&self, event: &dyn Any, cx: &App) -> bool {        event            .downcast_ref::<T::Event>()            .map_or(false, |event| self.read(cx).should_serialize(event))    }} pub trait ItemHandle: 'static + Send {    fn item_focus_handle(&self, cx: &App) -> FocusHandle;    fn subscribe_to_item_events(        &self,        window: &mut Window,        cx: &mut App,        handler: Box<dyn Fn(ItemEvent, &mut Window, &mut App)>,    ) -> gpui::Subscription;    fn tab_content(&self, params: TabContentParams, window: &Window, cx: &App) -> AnyElement;    fn tab_content_text(&self, detail: usize, cx: &App) -> SharedString;    fn tab_icon(&self, window: &Window, cx: &App) -> Option<Icon>;    fn tab_tooltip_text(&self, cx: &App) -> Option<SharedString>;    fn tab_tooltip_content(&self, cx: &App) -> Option<TabTooltipContent>;    fn telemetry_event_text(&self, cx: &App) -> Option<&'static str>;    fn dragged_tab_content(        &self,        params: TabContentParams,        window: &Window,        cx: &App,    ) -> AnyElement;    fn project_path(&self, cx: &App) -> Option<ProjectPath>;    fn project_entry_ids(&self, cx: &App) -> SmallVec<[ProjectEntryId; 3]>;    fn project_paths(&self, cx: &App) -> SmallVec<[ProjectPath; 3]>;    fn project_item_model_ids(&self, cx: &App) -> SmallVec<[EntityId; 3]>;    fn for_each_project_item(        &self,        _: &App,

Lines 1–500 of 1706.