mode_indicator.rs

 1use gpui::{div, Element, Render, Subscription, ViewContext};
 2use workspace::{item::ItemHandle, ui::prelude::*, StatusItemView};
 3
 4use crate::{state::Mode, Vim};
 5
 6/// The ModeIndicator displays the current mode in the status bar.
 7pub struct ModeIndicator {
 8    pub(crate) mode: Option<Mode>,
 9    pub(crate) operators: String,
10    _subscription: Subscription,
11}
12
13impl ModeIndicator {
14    /// Construct a new mode indicator in this window.
15    pub fn new(cx: &mut ViewContext<Self>) -> Self {
16        let _subscription = cx.observe_global::<Vim>(|this, cx| this.update_mode(cx));
17        let mut this = Self {
18            mode: None,
19            operators: "".to_string(),
20            _subscription,
21        };
22        this.update_mode(cx);
23        this
24    }
25
26    fn update_mode(&mut self, cx: &mut ViewContext<Self>) {
27        // Vim doesn't exist in some tests
28        let Some(vim) = cx.try_global::<Vim>() else {
29            return;
30        };
31
32        if vim.enabled {
33            self.mode = Some(vim.state().mode);
34            self.operators = self.current_operators_description(&vim);
35        } else {
36            self.mode = None;
37        }
38    }
39
40    fn current_operators_description(&self, vim: &Vim) -> String {
41        vim.state()
42            .pre_count
43            .map(|count| format!("{}", count))
44            .into_iter()
45            .chain(vim.state().selected_register.map(|reg| format!("\"{reg}")))
46            .chain(
47                vim.state()
48                    .operator_stack
49                    .iter()
50                    .map(|item| item.id().to_string()),
51            )
52            .chain(vim.state().post_count.map(|count| format!("{}", count)))
53            .collect::<Vec<_>>()
54            .join("")
55    }
56}
57
58impl Render for ModeIndicator {
59    fn render(&mut self, _: &mut ViewContext<Self>) -> impl IntoElement {
60        let Some(mode) = self.mode.as_ref() else {
61            return div().into_any();
62        };
63
64        Label::new(format!("{} -- {} --", self.operators, mode))
65            .size(LabelSize::Small)
66            .line_height_style(LineHeightStyle::UiLabel)
67            .into_any_element()
68    }
69}
70
71impl StatusItemView for ModeIndicator {
72    fn set_active_pane_item(
73        &mut self,
74        _active_pane_item: Option<&dyn ItemHandle>,
75        _cx: &mut ViewContext<Self>,
76    ) {
77        // nothing to do.
78    }
79}