1use std::sync::Arc;
2
3use assistant_tool::{ToolSource, ToolWorkingSet};
4use gpui::Entity;
5use ui::{prelude::*, ContextMenu, IconButtonShape, PopoverMenu, Tooltip};
6
7pub struct ToolSelector {
8 tools: Arc<ToolWorkingSet>,
9}
10
11impl ToolSelector {
12 pub fn new(tools: Arc<ToolWorkingSet>, _cx: &mut Context<Self>) -> Self {
13 Self { tools }
14 }
15
16 fn build_context_menu(
17 &self,
18 window: &mut Window,
19 cx: &mut Context<Self>,
20 ) -> Entity<ContextMenu> {
21 ContextMenu::build(window, cx, |mut menu, _window, cx| {
22 let tools_by_source = self.tools.tools_by_source(cx);
23
24 for (source, tools) in tools_by_source {
25 menu = match source {
26 ToolSource::Native => menu.header("Zed"),
27 ToolSource::ContextServer { id } => menu.separator().header(id),
28 };
29
30 for tool in tools {
31 let source = tool.source();
32 let name = tool.name().into();
33 let is_enabled = self.tools.is_enabled(&source, &name);
34
35 menu =
36 menu.toggleable_entry(tool.name(), is_enabled, IconPosition::End, None, {
37 let tools = self.tools.clone();
38 move |_window, _cx| {
39 if is_enabled {
40 tools.disable(source.clone(), &[name.clone()]);
41 } else {
42 tools.enable(source.clone(), &[name.clone()]);
43 }
44 }
45 });
46 }
47 }
48
49 menu
50 })
51 }
52}
53
54impl Render for ToolSelector {
55 fn render(&mut self, _window: &mut Window, cx: &mut Context<'_, Self>) -> impl IntoElement {
56 let this = cx.entity().clone();
57 PopoverMenu::new("tool-selector")
58 .menu(move |window, cx| {
59 Some(this.update(cx, |this, cx| this.build_context_menu(window, cx)))
60 })
61 .trigger_with_tooltip(
62 IconButton::new("tool-selector-button", IconName::SettingsAlt)
63 .shape(IconButtonShape::Square)
64 .icon_size(IconSize::Small)
65 .icon_color(Color::Muted),
66 Tooltip::text("Customize Tools"),
67 )
68 .anchor(gpui::Corner::BottomLeft)
69 }
70}