1use editor::Editor;
2use gpui::{
3 Context, Entity, IntoElement, ParentElement, Render, Styled, Subscription, WeakEntity, Window,
4 div,
5};
6use language::LanguageName;
7use settings::Settings as _;
8use ui::{Button, ButtonCommon, Clickable, FluentBuilder, LabelSize, Tooltip};
9use workspace::{StatusBarSettings, StatusItemView, Workspace, item::ItemHandle};
10
11use crate::{LanguageSelector, Toggle};
12
13pub struct ActiveBufferLanguage {
14 active_language: Option<Option<LanguageName>>,
15 workspace: WeakEntity<Workspace>,
16 _observe_active_editor: Option<Subscription>,
17}
18
19impl ActiveBufferLanguage {
20 pub fn new(workspace: &Workspace) -> Self {
21 Self {
22 active_language: None,
23 workspace: workspace.weak_handle(),
24 _observe_active_editor: None,
25 }
26 }
27
28 fn update_language(&mut self, editor: Entity<Editor>, _: &mut Window, cx: &mut Context<Self>) {
29 self.active_language = Some(None);
30
31 let editor = editor.read(cx);
32 if let Some((_, buffer, _)) = editor.active_excerpt(cx)
33 && let Some(language) = buffer.read(cx).language()
34 {
35 self.active_language = Some(Some(language.name()));
36 }
37
38 cx.notify();
39 }
40}
41
42impl Render for ActiveBufferLanguage {
43 fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
44 if !StatusBarSettings::get_global(cx).active_language_button {
45 return div().hidden();
46 }
47
48 div().when_some(self.active_language.as_ref(), |el, active_language| {
49 let active_language_text = if let Some(active_language_text) = active_language {
50 active_language_text.to_string()
51 } else {
52 "Unknown".to_string()
53 };
54
55 el.child(
56 Button::new("change-language", active_language_text)
57 .label_size(LabelSize::Small)
58 .on_click(cx.listener(|this, _, window, cx| {
59 if let Some(workspace) = this.workspace.upgrade() {
60 workspace.update(cx, |workspace, cx| {
61 LanguageSelector::toggle(workspace, window, cx)
62 });
63 }
64 }))
65 .tooltip(|_window, cx| Tooltip::for_action("Select Language", &Toggle, cx)),
66 )
67 })
68 }
69}
70
71impl StatusItemView for ActiveBufferLanguage {
72 fn set_active_pane_item(
73 &mut self,
74 active_pane_item: Option<&dyn ItemHandle>,
75 window: &mut Window,
76 cx: &mut Context<Self>,
77 ) {
78 if let Some(editor) = active_pane_item.and_then(|item| item.downcast::<Editor>()) {
79 self._observe_active_editor =
80 Some(cx.observe_in(&editor, window, Self::update_language));
81 self.update_language(editor, window, cx);
82 } else {
83 self.active_language = None;
84 self._observe_active_editor = None;
85 }
86
87 cx.notify();
88 }
89}