626 lines · 20.7 KB · Rust
RawDownload
use std::fmt::Display; use gpui::{    App, Context, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,    KeyContext, ModifiersChangedEvent, MouseButton, ParentElement, Rems, Render, Styled,    Subscription, WeakEntity, Window, actions, rems,};use project::git_store::Repository;use ui::{    FluentBuilder, ToggleButtonGroup, ToggleButtonGroupStyle, ToggleButtonSimple, Tooltip,    prelude::*,};use workspace::{ModalView, Workspace, pane}; use crate::branch_picker::{self, BranchList, DeleteBranch, FilterRemotes};use crate::stash_picker::{self, DropStashItem, ShowStashItem, StashList};use crate::worktree_picker::{    self, DeleteWorktree, WorktreeFromDefault, WorktreeFromDefaultOnWindow, WorktreeList,}; actions!(    git_picker,    [ActivateBranchesTab, ActivateWorktreesTab, ActivateStashTab,]); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]pub enum GitPickerTab {    Branches,    Worktrees,    Stash,} impl Display for GitPickerTab {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        let label = match self {            GitPickerTab::Branches => "Branches",            GitPickerTab::Worktrees => "Worktrees",            GitPickerTab::Stash => "Stash",        };        write!(f, "{}", label)    }} pub struct GitPicker {    tab: GitPickerTab,    workspace: WeakEntity<Workspace>,    repository: Option<Entity<Repository>>,    width: Rems,    branch_list: Option<Entity<BranchList>>,    worktree_list: Option<Entity<WorktreeList>>,    stash_list: Option<Entity<StashList>>,    _subscriptions: Vec<Subscription>,    popover_style: bool,} impl GitPicker {    pub fn new(        workspace: WeakEntity<Workspace>,        repository: Option<Entity<Repository>>,        initial_tab: GitPickerTab,        width: Rems,        window: &mut Window,        cx: &mut Context<Self>,    ) -> Self {        Self::new_internal(workspace, repository, initial_tab, width, false, window, cx)    }     fn new_internal(        workspace: WeakEntity<Workspace>,        repository: Option<Entity<Repository>>,        initial_tab: GitPickerTab,        width: Rems,        popover_style: bool,        window: &mut Window,        cx: &mut Context<Self>,    ) -> Self {        let mut this = Self {            tab: initial_tab,            workspace,            repository,            width,            branch_list: None,            worktree_list: None,            stash_list: None,            _subscriptions: Vec::new(),            popover_style,        };         this.ensure_active_picker(window, cx);        this    }     fn ensure_active_picker(&mut self, window: &mut Window, cx: &mut Context<Self>) {        match self.tab {            GitPickerTab::Branches => {                self.ensure_branch_list(window, cx);            }            GitPickerTab::Worktrees => {                self.ensure_worktree_list(window, cx);            }            GitPickerTab::Stash => {                self.ensure_stash_list(window, cx);            }        }    }     fn ensure_branch_list(        &mut self,        window: &mut Window,        cx: &mut Context<Self>,    ) -> Entity<BranchList> {        if self.branch_list.is_none() {            let branch_list = cx.new(|cx| {                branch_picker::create_embedded(                    self.workspace.clone(),                    self.repository.clone(),                    self.width,                    window,                    cx,                )            });             let subscription = cx.subscribe(&branch_list, |this, _, _: &DismissEvent, cx| {                if this.tab == GitPickerTab::Branches {                    cx.emit(DismissEvent);                }            });             self._subscriptions.push(subscription);            self.branch_list = Some(branch_list);        }        self.branch_list.clone().unwrap()    }     fn ensure_worktree_list(        &mut self,        window: &mut Window,        cx: &mut Context<Self>,    ) -> Entity<WorktreeList> {        if self.worktree_list.is_none() {            let worktree_list = cx.new(|cx| {                worktree_picker::create_embedded(                    self.repository.clone(),                    self.workspace.clone(),                    self.width,                    window,                    cx,                )            });             let subscription = cx.subscribe(&worktree_list, |this, _, _: &DismissEvent, cx| {                if this.tab == GitPickerTab::Worktrees {                    cx.emit(DismissEvent);                }            });             self._subscriptions.push(subscription);            self.worktree_list = Some(worktree_list);        }        self.worktree_list.clone().unwrap()    }     fn ensure_stash_list(        &mut self,        window: &mut Window,        cx: &mut Context<Self>,    ) -> Entity<StashList> {        if self.stash_list.is_none() {            let stash_list = cx.new(|cx| {                stash_picker::create_embedded(                    self.repository.clone(),                    self.workspace.clone(),                    self.width,                    window,                    cx,                )            });             let subscription = cx.subscribe(&stash_list, |this, _, _: &DismissEvent, cx| {                if this.tab == GitPickerTab::Stash {                    cx.emit(DismissEvent);                }            });             self._subscriptions.push(subscription);            self.stash_list = Some(stash_list);        }        self.stash_list.clone().unwrap()    }     fn activate_next_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) {        self.tab = match self.tab {            GitPickerTab::Branches => GitPickerTab::Worktrees,            GitPickerTab::Worktrees => GitPickerTab::Stash,            GitPickerTab::Stash => GitPickerTab::Branches,        };        self.ensure_active_picker(window, cx);        self.focus_active_picker(window, cx);        cx.notify();    }     fn activate_previous_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) {        self.tab = match self.tab {            GitPickerTab::Branches => GitPickerTab::Stash,            GitPickerTab::Worktrees => GitPickerTab::Branches,            GitPickerTab::Stash => GitPickerTab::Worktrees,        };        self.ensure_active_picker(window, cx);        self.focus_active_picker(window, cx);        cx.notify();    }     fn focus_active_picker(&self, window: &mut Window, cx: &mut App) {        match self.tab {            GitPickerTab::Branches => {                if let Some(branch_list) = &self.branch_list {                    branch_list.focus_handle(cx).focus(window, cx);                }            }            GitPickerTab::Worktrees => {                if let Some(worktree_list) = &self.worktree_list {                    worktree_list.focus_handle(cx).focus(window, cx);                }            }            GitPickerTab::Stash => {                if let Some(stash_list) = &self.stash_list {                    stash_list.focus_handle(cx).focus(window, cx);                }            }        }    }     fn render_tab_bar(&self, cx: &mut Context<Self>) -> impl IntoElement {        let focus_handle = self.focus_handle(cx);        let branches_focus_handle = focus_handle.clone();        let worktrees_focus_handle = focus_handle.clone();        let stash_focus_handle = focus_handle;         h_flex().p_2().pb_0p5().w_full().child(            ToggleButtonGroup::single_row(                "git-picker-tabs",                [                    ToggleButtonSimple::new(                        GitPickerTab::Branches.to_string(),                        cx.listener(|this, _, window, cx| {                            this.tab = GitPickerTab::Branches;                            this.ensure_active_picker(window, cx);                            this.focus_active_picker(window, cx);                            cx.notify();                        }),                    )                    .tooltip(move |_, cx| {                        Tooltip::for_action_in(                            "Toggle Branch Picker",                            &ActivateBranchesTab,                            &branches_focus_handle,                            cx,                        )                    }),                    ToggleButtonSimple::new(                        GitPickerTab::Worktrees.to_string(),                        cx.listener(|this, _, window, cx| {                            this.tab = GitPickerTab::Worktrees;                            this.ensure_active_picker(window, cx);                            this.focus_active_picker(window, cx);                            cx.notify();                        }),                    )                    .tooltip(move |_, cx| {                        Tooltip::for_action_in(                            "Toggle Worktree Picker",                            &ActivateWorktreesTab,                            &worktrees_focus_handle,                            cx,                        )                    }),                    ToggleButtonSimple::new(                        GitPickerTab::Stash.to_string(),                        cx.listener(|this, _, window, cx| {                            this.tab = GitPickerTab::Stash;                            this.ensure_active_picker(window, cx);                            this.focus_active_picker(window, cx);                            cx.notify();                        }),                    )                    .tooltip(move |_, cx| {                        Tooltip::for_action_in(                            "Toggle Stash Picker",                            &ActivateStashTab,                            &stash_focus_handle,                            cx,                        )                    }),                ],            )            .label_size(LabelSize::Default)            .style(ToggleButtonGroupStyle::Outlined)            .auto_width()            .selected_index(match self.tab {                GitPickerTab::Branches => 0,                GitPickerTab::Worktrees => 1,                GitPickerTab::Stash => 2,            }),        )    }     fn render_active_picker(        &mut self,        window: &mut Window,        cx: &mut Context<Self>,    ) -> impl IntoElement {        match self.tab {            GitPickerTab::Branches => {                let branch_list = self.ensure_branch_list(window, cx);                branch_list.into_any_element()            }            GitPickerTab::Worktrees => {                let worktree_list = self.ensure_worktree_list(window, cx);                worktree_list.into_any_element()            }            GitPickerTab::Stash => {                let stash_list = self.ensure_stash_list(window, cx);                stash_list.into_any_element()            }        }    }     fn handle_modifiers_changed(        &mut self,        ev: &ModifiersChangedEvent,        window: &mut Window,        cx: &mut Context<Self>,    ) {        match self.tab {            GitPickerTab::Branches => {                if let Some(branch_list) = &self.branch_list {                    branch_list.update(cx, |list, cx| {                        list.handle_modifiers_changed(ev, window, cx);                    });                }            }            GitPickerTab::Worktrees => {                if let Some(worktree_list) = &self.worktree_list {                    worktree_list.update(cx, |list, cx| {                        list.handle_modifiers_changed(ev, window, cx);                    });                }            }            GitPickerTab::Stash => {                if let Some(stash_list) = &self.stash_list {                    stash_list.update(cx, |list, cx| {                        list.handle_modifiers_changed(ev, window, cx);                    });                }            }        }    }     fn handle_delete_branch(        &mut self,        _: &DeleteBranch,        window: &mut Window,        cx: &mut Context<Self>,    ) {        if let Some(branch_list) = &self.branch_list {            branch_list.update(cx, |list, cx| {                list.handle_delete(&DeleteBranch, window, cx);            });        }    }     fn handle_filter_remotes(        &mut self,        _: &FilterRemotes,        window: &mut Window,        cx: &mut Context<Self>,    ) {        if let Some(branch_list) = &self.branch_list {            branch_list.update(cx, |list, cx| {                list.handle_filter(&FilterRemotes, window, cx);            });        }    }     fn handle_worktree_from_default(        &mut self,        _: &WorktreeFromDefault,        window: &mut Window,        cx: &mut Context<Self>,    ) {        if let Some(worktree_list) = &self.worktree_list {            worktree_list.update(cx, |list, cx| {                list.handle_new_worktree(false, window, cx);            });        }    }     fn handle_worktree_from_default_on_window(        &mut self,        _: &WorktreeFromDefaultOnWindow,        window: &mut Window,        cx: &mut Context<Self>,    ) {        if let Some(worktree_list) = &self.worktree_list {            worktree_list.update(cx, |list, cx| {                list.handle_new_worktree(true, window, cx);            });        }    }     fn handle_worktree_delete(        &mut self,        _: &DeleteWorktree,        window: &mut Window,        cx: &mut Context<Self>,    ) {        if let Some(worktree_list) = &self.worktree_list {            worktree_list.update(cx, |list, cx| {                list.handle_delete(&DeleteWorktree, window, cx);            });        }    }     fn handle_drop_stash(        &mut self,        _: &DropStashItem,        window: &mut Window,        cx: &mut Context<Self>,    ) {        if let Some(stash_list) = &self.stash_list {            stash_list.update(cx, |list, cx| {                list.handle_drop_stash(&DropStashItem, window, cx);            });        }    }     fn handle_show_stash(        &mut self,        _: &ShowStashItem,        window: &mut Window,        cx: &mut Context<Self>,    ) {        if let Some(stash_list) = &self.stash_list {            stash_list.update(cx, |list, cx| {                list.handle_show_stash(&ShowStashItem, window, cx);            });        }    }} impl ModalView for GitPicker {}impl EventEmitter<DismissEvent> for GitPicker {} impl Focusable for GitPicker {    fn focus_handle(&self, cx: &App) -> FocusHandle {        match self.tab {            GitPickerTab::Branches => {                if let Some(branch_list) = &self.branch_list {                    return branch_list.focus_handle(cx);                }            }            GitPickerTab::Worktrees => {                if let Some(worktree_list) = &self.worktree_list {                    return worktree_list.focus_handle(cx);                }            }            GitPickerTab::Stash => {                if let Some(stash_list) = &self.stash_list {                    return stash_list.focus_handle(cx);                }            }        }        cx.focus_handle()    }} impl Render for GitPicker {    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {        v_flex()            .occlude()            .w(self.width)            .elevation_3(cx)            .overflow_hidden()            .when(self.popover_style, |el| {                el.on_mouse_down_out(cx.listener(|_, _, _, cx| {                    cx.emit(DismissEvent);                }))            })            .key_context({                let mut key_context = KeyContext::new_with_defaults();                key_context.add("Pane");                key_context.add("GitPicker");                match self.tab {                    GitPickerTab::Branches => key_context.add("GitBranchSelector"),                    GitPickerTab::Worktrees => key_context.add("GitWorktreeSelector"),                    GitPickerTab::Stash => key_context.add("StashList"),                }                key_context            })            .on_mouse_down(MouseButton::Left, |_, _, cx| {

Lines 1–500 of 626.