diff --git a/crates/language_selector/src/active_buffer_language.rs b/crates/language_selector/src/active_buffer_language.rs new file mode 100644 index 0000000000..c4129d1448 --- /dev/null +++ b/crates/language_selector/src/active_buffer_language.rs @@ -0,0 +1,86 @@ +use editor::Editor; +use gpui::{ + elements::*, CursorStyle, Entity, MouseButton, RenderContext, Subscription, View, ViewContext, + ViewHandle, +}; +use settings::Settings; +use std::sync::Arc; +use workspace::{item::ItemHandle, StatusItemView}; + +pub struct ActiveBufferLanguage { + active_language: Option>, + _observe_active_editor: Option, +} + +impl Default for ActiveBufferLanguage { + fn default() -> Self { + Self::new() + } +} + +impl ActiveBufferLanguage { + pub fn new() -> Self { + Self { + active_language: None, + _observe_active_editor: None, + } + } + + fn update_language(&mut self, editor: ViewHandle, cx: &mut ViewContext) { + let editor = editor.read(cx); + self.active_language.take(); + if let Some((_, buffer, _)) = editor.active_excerpt(cx) { + if let Some(language) = buffer.read(cx).language() { + self.active_language = Some(language.name()); + } + } + + cx.notify(); + } +} + +impl Entity for ActiveBufferLanguage { + type Event = (); +} + +impl View for ActiveBufferLanguage { + fn ui_name() -> &'static str { + "ActiveBufferLanguage" + } + + fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + if let Some(active_language) = self.active_language.as_ref() { + MouseEventHandler::::new(0, cx, |state, cx| { + let theme = &cx.global::().theme.workspace.status_bar; + let style = theme.active_language.style_for(state, false); + Label::new(active_language.to_string(), style.text.clone()) + .contained() + .with_style(style.container) + .boxed() + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(crate::Toggle)) + .boxed() + } else { + Empty::new().boxed() + } + } +} + +impl StatusItemView for ActiveBufferLanguage { + fn set_active_pane_item( + &mut self, + active_pane_item: Option<&dyn ItemHandle>, + cx: &mut ViewContext, + ) { + if let Some(editor) = active_pane_item.and_then(|item| item.act_as::(cx)) { + self._observe_active_editor = Some(cx.observe(&editor, Self::update_language)); + self.update_language(editor, cx); + } else { + self.active_language = None; + self._observe_active_editor = None; + } + + cx.notify(); + } +} diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs index 786dd5abe0..711e36f9c4 100644 --- a/crates/language_selector/src/language_selector.rs +++ b/crates/language_selector/src/language_selector.rs @@ -1,5 +1,6 @@ -use std::sync::Arc; +mod active_buffer_language; +pub use active_buffer_language::ActiveBufferLanguage; use editor::Editor; use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; use gpui::{ @@ -10,6 +11,7 @@ use language::{Buffer, LanguageRegistry}; use picker::{Picker, PickerDelegate}; use project::Project; use settings::Settings; +use std::sync::Arc; use workspace::{AppState, Workspace}; actions!(language_selector, [Toggle]); diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 56ef87e0af..aa379bf838 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -277,6 +277,7 @@ pub struct StatusBar { pub height: f32, pub item_spacing: f32, pub cursor_position: TextStyle, + pub active_language: Interactive, pub auto_update_progress_message: TextStyle, pub auto_update_done_message: TextStyle, pub lsp_status: Interactive, diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index f853e41c04..664833de1e 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -338,6 +338,7 @@ pub fn initialize_workspace( cx.add_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace.project(), cx)); let activity_indicator = activity_indicator::ActivityIndicator::new(workspace, app_state.languages.clone(), cx); + let active_buffer_language = cx.add_view(|_| language_selector::ActiveBufferLanguage::new()); let cursor_position = cx.add_view(|_| editor::items::CursorPosition::new()); let feedback_button = cx.add_view(|_| feedback::deploy_feedback_button::DeployFeedbackButton {}); @@ -346,6 +347,7 @@ pub fn initialize_workspace( status_bar.add_left_item(diagnostic_summary, cx); status_bar.add_left_item(activity_indicator, cx); status_bar.add_right_item(cursor_position, cx); + status_bar.add_right_item(active_buffer_language, cx); }); auto_update::notify_of_any_new_update(cx.weak_handle(), cx); diff --git a/styles/src/styleTree/statusBar.ts b/styles/src/styleTree/statusBar.ts index eb72346788..de33f3d1d5 100644 --- a/styles/src/styleTree/statusBar.ts +++ b/styles/src/styleTree/statusBar.ts @@ -25,6 +25,12 @@ export default function statusBar(colorScheme: ColorScheme) { }, border: border(layer, { top: true, overlay: true }), cursorPosition: text(layer, "sans", "variant"), + activeLanguage: { + ...text(layer, "sans", "variant"), + hover: { + ...text(layer, "sans", "on") + } + }, autoUpdateProgressMessage: text(layer, "sans", "variant"), autoUpdateDoneMessage: text(layer, "sans", "variant"), lspStatus: { @@ -45,9 +51,10 @@ export default function statusBar(colorScheme: ColorScheme) { hover: text(layer, "sans", "hovered"), }, feedback: { + margin: { left: 2 }, color: foreground(layer, "variant"), iconWidth: 14, - buttonWidth: 20, + buttonWidth: 14, hover: { color: foreground(layer, "on"), },