git_panel.rs

  1use gpui::*;
  2use ui::{prelude::*, Checkbox, Divider, DividerColor, ElevationIndex};
  3use workspace::dock::{DockPosition, Panel, PanelEvent};
  4use workspace::Workspace;
  5
  6pub fn init(cx: &mut AppContext) {
  7    cx.observe_new_views(
  8        |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
  9            workspace.register_action(|workspace, _: &ToggleFocus, cx| {
 10                workspace.toggle_panel_focus::<GitPanel>(cx);
 11            });
 12        },
 13    )
 14    .detach();
 15}
 16
 17actions!(git_panel, [Deploy, ToggleFocus]);
 18
 19#[derive(Clone)]
 20pub struct GitPanel {
 21    _workspace: WeakView<Workspace>,
 22    focus_handle: FocusHandle,
 23    width: Option<Pixels>,
 24}
 25
 26impl GitPanel {
 27    pub fn load(
 28        workspace: WeakView<Workspace>,
 29        cx: AsyncWindowContext,
 30    ) -> Task<Result<View<Self>>> {
 31        cx.spawn(|mut cx| async move {
 32            workspace.update(&mut cx, |workspace, cx| {
 33                let workspace_handle = workspace.weak_handle();
 34
 35                cx.new_view(|cx| Self::new(workspace_handle, cx))
 36            })
 37        })
 38    }
 39
 40    pub fn new(workspace: WeakView<Workspace>, cx: &mut ViewContext<Self>) -> Self {
 41        Self {
 42            _workspace: workspace,
 43            focus_handle: cx.focus_handle(),
 44            width: Some(px(360.)),
 45        }
 46    }
 47
 48    pub fn render_panel_header(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
 49        h_flex()
 50            .h(px(32.))
 51            .items_center()
 52            .px_3()
 53            .bg(ElevationIndex::Surface.bg(cx))
 54            .child(
 55                h_flex()
 56                    .gap_1()
 57                    .child(Checkbox::new("all-changes", true.into()).disabled(true))
 58                    .child(div().text_buffer(cx).text_ui_sm(cx).child("0 changes")),
 59            )
 60            .child(div().flex_grow())
 61            .child(
 62                h_flex()
 63                    .gap_1()
 64                    .child(
 65                        IconButton::new("discard-changes", IconName::Undo)
 66                            .icon_size(IconSize::Small)
 67                            .disabled(true),
 68                    )
 69                    .child(
 70                        Button::new("stage-all", "Stage All")
 71                            .label_size(LabelSize::Small)
 72                            .layer(ElevationIndex::ElevatedSurface)
 73                            .size(ButtonSize::Compact)
 74                            .style(ButtonStyle::Filled)
 75                            .disabled(true),
 76                    ),
 77            )
 78    }
 79
 80    pub fn render_commit_editor(&self, cx: &ViewContext<Self>) -> impl IntoElement {
 81        div().w_full().h(px(140.)).px_2().pt_1().pb_2().child(
 82            v_flex()
 83                .h_full()
 84                .py_2p5()
 85                .px_3()
 86                .bg(cx.theme().colors().editor_background)
 87                .font_buffer(cx)
 88                .text_ui_sm(cx)
 89                .text_color(cx.theme().colors().text_muted)
 90                .child("Add a message")
 91                .gap_1()
 92                .child(div().flex_grow())
 93                .child(
 94                    h_flex().child(div().gap_1().flex_grow()).child(
 95                        Button::new("commit", "Commit")
 96                            .label_size(LabelSize::Small)
 97                            .layer(ElevationIndex::ElevatedSurface)
 98                            .size(ButtonSize::Compact)
 99                            .style(ButtonStyle::Filled)
100                            .disabled(true),
101                    ),
102                )
103                .cursor(CursorStyle::OperationNotAllowed)
104                .opacity(0.5),
105        )
106    }
107}
108
109impl Render for GitPanel {
110    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
111        v_flex()
112            .key_context("GitPanel")
113            .font_buffer(cx)
114            .py_1()
115            .id("git_panel")
116            .track_focus(&self.focus_handle)
117            .size_full()
118            .overflow_hidden()
119            .bg(ElevationIndex::Surface.bg(cx))
120            .child(self.render_panel_header(cx))
121            .child(
122                h_flex()
123                    .items_center()
124                    .h(px(8.))
125                    .child(Divider::horizontal_dashed().color(DividerColor::Border)),
126            )
127            .child(div().flex_1())
128            .child(
129                h_flex()
130                    .items_center()
131                    .h(px(8.))
132                    .child(Divider::horizontal_dashed().color(DividerColor::Border)),
133            )
134            .child(self.render_commit_editor(cx))
135    }
136}
137
138impl FocusableView for GitPanel {
139    fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle {
140        self.focus_handle.clone()
141    }
142}
143
144impl EventEmitter<PanelEvent> for GitPanel {}
145
146impl Panel for GitPanel {
147    fn persistent_name() -> &'static str {
148        "GitPanel"
149    }
150
151    fn position(&self, _cx: &gpui::WindowContext) -> DockPosition {
152        DockPosition::Left
153    }
154
155    fn position_is_valid(&self, position: DockPosition) -> bool {
156        matches!(position, DockPosition::Left | DockPosition::Right)
157    }
158
159    fn set_position(&mut self, _position: DockPosition, _cx: &mut ViewContext<Self>) {}
160
161    fn size(&self, _cx: &gpui::WindowContext) -> Pixels {
162        self.width.unwrap_or(px(360.))
163    }
164
165    fn set_size(&mut self, size: Option<Pixels>, cx: &mut ViewContext<Self>) {
166        self.width = size;
167        cx.notify();
168    }
169
170    fn icon(&self, _cx: &gpui::WindowContext) -> Option<ui::IconName> {
171        Some(ui::IconName::GitBranch)
172    }
173
174    fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> {
175        Some("Git Panel")
176    }
177
178    fn toggle_action(&self) -> Box<dyn Action> {
179        Box::new(ToggleFocus)
180    }
181}