context_strip.rs

  1use std::rc::Rc;
  2
  3use gpui::{FocusHandle, Model, View, WeakModel, WeakView};
  4use ui::{prelude::*, PopoverMenu, PopoverMenuHandle, Tooltip};
  5use workspace::Workspace;
  6
  7use crate::context_picker::{ConfirmBehavior, ContextPicker};
  8use crate::context_store::ContextStore;
  9use crate::thread_store::ThreadStore;
 10use crate::ui::ContextPill;
 11use crate::ToggleContextPicker;
 12
 13pub struct ContextStrip {
 14    context_store: Model<ContextStore>,
 15    context_picker: View<ContextPicker>,
 16    context_picker_menu_handle: PopoverMenuHandle<ContextPicker>,
 17    focus_handle: FocusHandle,
 18}
 19
 20impl ContextStrip {
 21    pub fn new(
 22        context_store: Model<ContextStore>,
 23        workspace: WeakView<Workspace>,
 24        thread_store: Option<WeakModel<ThreadStore>>,
 25        focus_handle: FocusHandle,
 26        context_picker_menu_handle: PopoverMenuHandle<ContextPicker>,
 27        cx: &mut ViewContext<Self>,
 28    ) -> Self {
 29        Self {
 30            context_store: context_store.clone(),
 31            context_picker: cx.new_view(|cx| {
 32                ContextPicker::new(
 33                    workspace.clone(),
 34                    thread_store.clone(),
 35                    context_store.downgrade(),
 36                    ConfirmBehavior::KeepOpen,
 37                    cx,
 38                )
 39            }),
 40            context_picker_menu_handle,
 41            focus_handle,
 42        }
 43    }
 44}
 45
 46impl Render for ContextStrip {
 47    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
 48        let context = self.context_store.read(cx).context();
 49        let context_picker = self.context_picker.clone();
 50        let focus_handle = self.focus_handle.clone();
 51
 52        h_flex()
 53            .flex_wrap()
 54            .gap_1()
 55            .child(
 56                PopoverMenu::new("context-picker")
 57                    .menu(move |_cx| Some(context_picker.clone()))
 58                    .trigger(
 59                        IconButton::new("add-context", IconName::Plus)
 60                            .icon_size(IconSize::Small)
 61                            .style(ui::ButtonStyle::Filled)
 62                            .tooltip(move |cx| {
 63                                Tooltip::for_action_in(
 64                                    "Add Context",
 65                                    &ToggleContextPicker,
 66                                    &focus_handle,
 67                                    cx,
 68                                )
 69                            }),
 70                    )
 71                    .attach(gpui::Corner::TopLeft)
 72                    .anchor(gpui::Corner::BottomLeft)
 73                    .offset(gpui::Point {
 74                        x: px(0.0),
 75                        y: px(-16.0),
 76                    })
 77                    .with_handle(self.context_picker_menu_handle.clone()),
 78            )
 79            .children(context.iter().map(|context| {
 80                ContextPill::new(context.clone()).on_remove({
 81                    let context = context.clone();
 82                    let context_store = self.context_store.clone();
 83                    Rc::new(cx.listener(move |_this, _event, cx| {
 84                        context_store.update(cx, |this, _cx| {
 85                            this.remove_context(&context.id);
 86                        });
 87                        cx.notify();
 88                    }))
 89                })
 90            }))
 91            .when(!context.is_empty(), |parent| {
 92                parent.child(
 93                    IconButton::new("remove-all-context", IconName::Eraser)
 94                        .icon_size(IconSize::Small)
 95                        .tooltip(move |cx| Tooltip::text("Remove All Context", cx))
 96                        .on_click({
 97                            let context_store = self.context_store.clone();
 98                            cx.listener(move |_this, _event, cx| {
 99                                context_store.update(cx, |this, _cx| this.clear());
100                                cx.notify();
101                            })
102                        }),
103                )
104            })
105    }
106}