1use gpui::{div, Element, Render, Subscription, ViewContext};
2use settings::SettingsStore;
3use workspace::{item::ItemHandle, ui::prelude::*, StatusItemView};
4
5use crate::{state::Mode, Vim};
6
7pub struct ModeIndicator {
8 pub mode: Option<Mode>,
9 _subscriptions: Vec<Subscription>,
10}
11
12impl ModeIndicator {
13 pub fn new(cx: &mut ViewContext<Self>) -> Self {
14 let _subscriptions = vec![
15 cx.observe_global::<Vim>(|this, cx| this.update_mode(cx)),
16 cx.observe_global::<SettingsStore>(|this, cx| this.update_mode(cx)),
17 ];
18
19 let mut this = Self {
20 mode: None,
21 _subscriptions,
22 };
23 this.update_mode(cx);
24 this
25 }
26
27 fn update_mode(&mut self, cx: &mut ViewContext<Self>) {
28 // Vim doesn't exist in some tests
29 if !cx.has_global::<Vim>() {
30 return;
31 }
32
33 let vim = Vim::read(cx);
34 if vim.enabled {
35 self.mode = Some(vim.state().mode);
36 } else {
37 self.mode = None;
38 }
39 }
40
41 pub fn set_mode(&mut self, mode: Mode, cx: &mut ViewContext<Self>) {
42 if self.mode != Some(mode) {
43 self.mode = Some(mode);
44 cx.notify();
45 }
46 }
47}
48
49impl Render for ModeIndicator {
50 fn render(&mut self, _: &mut ViewContext<Self>) -> impl IntoElement {
51 let Some(mode) = self.mode.as_ref() else {
52 return div().into_any();
53 };
54
55 let text = match mode {
56 Mode::Normal => "-- NORMAL --",
57 Mode::Insert => "-- INSERT --",
58 Mode::Visual => "-- VISUAL --",
59 Mode::VisualLine => "-- VISUAL LINE --",
60 Mode::VisualBlock => "-- VISUAL BLOCK --",
61 };
62 Label::new(text).size(LabelSize::Small).into_any_element()
63 }
64}
65
66impl StatusItemView for ModeIndicator {
67 fn set_active_pane_item(
68 &mut self,
69 _active_pane_item: Option<&dyn ItemHandle>,
70 _cx: &mut ViewContext<Self>,
71 ) {
72 // nothing to do.
73 }
74}