1use std::sync::Arc;
2
3use crate::{assistant_settings::AssistantSettings, CompletionProvider, ToggleModelSelector};
4use fs::Fs;
5use settings::update_settings_file;
6use ui::{prelude::*, ButtonLike, ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip};
7
8#[derive(IntoElement)]
9pub struct ModelSelector {
10 handle: PopoverMenuHandle<ContextMenu>,
11 fs: Arc<dyn Fs>,
12}
13
14impl ModelSelector {
15 pub fn new(handle: PopoverMenuHandle<ContextMenu>, fs: Arc<dyn Fs>) -> Self {
16 ModelSelector { handle, fs }
17 }
18}
19
20impl RenderOnce for ModelSelector {
21 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
22 PopoverMenu::new("model-switcher")
23 .with_handle(self.handle)
24 .menu(move |cx| {
25 ContextMenu::build(cx, |mut menu, cx| {
26 for model in CompletionProvider::global(cx).available_models(cx) {
27 menu = menu.custom_entry(
28 {
29 let model = model.clone();
30 move |_| Label::new(model.display_name()).into_any_element()
31 },
32 {
33 let fs = self.fs.clone();
34 let model = model.clone();
35 move |cx| {
36 let model = model.clone();
37 update_settings_file::<AssistantSettings>(
38 fs.clone(),
39 cx,
40 move |settings| settings.set_model(model),
41 );
42 }
43 },
44 );
45 }
46 menu
47 })
48 .into()
49 })
50 .trigger(
51 ButtonLike::new("active-model")
52 .child(
53 h_flex()
54 .w_full()
55 .gap_0p5()
56 .child(
57 div()
58 .overflow_x_hidden()
59 .flex_grow()
60 .whitespace_nowrap()
61 .child(
62 Label::new(
63 CompletionProvider::global(cx).model().display_name(),
64 )
65 .size(LabelSize::Small)
66 .color(Color::Muted),
67 ),
68 )
69 .child(
70 div().child(
71 Icon::new(IconName::ChevronDown)
72 .color(Color::Muted)
73 .size(IconSize::XSmall),
74 ),
75 ),
76 )
77 .style(ButtonStyle::Subtle)
78 .tooltip(move |cx| {
79 Tooltip::for_action("Change Model", &ToggleModelSelector, cx)
80 }),
81 )
82 .anchor(gpui::AnchorCorner::BottomRight)
83 }
84}