context_strip.rs

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