2023-07-27 22:27:36 +00:00
|
|
|
use gpui::{
|
|
|
|
elements::{Empty, Label},
|
|
|
|
AnyElement, Element, Entity, Subscription, View, ViewContext,
|
|
|
|
};
|
|
|
|
use settings::SettingsStore;
|
2023-07-20 18:32:27 +00:00
|
|
|
use workspace::{item::ItemHandle, StatusItemView};
|
|
|
|
|
2023-07-27 22:27:36 +00:00
|
|
|
use crate::{state::Mode, Vim, VimEvent, VimModeSetting};
|
2023-07-20 18:32:27 +00:00
|
|
|
|
|
|
|
pub struct ModeIndicator {
|
2023-07-27 22:27:36 +00:00
|
|
|
pub mode: Option<Mode>,
|
|
|
|
_subscription: Subscription,
|
2023-07-20 18:32:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ModeIndicator {
|
2023-07-27 22:27:36 +00:00
|
|
|
pub fn new(cx: &mut ViewContext<Self>) -> Self {
|
|
|
|
let handle = cx.handle().downgrade();
|
|
|
|
|
|
|
|
let _subscription = cx.subscribe_global::<VimEvent, _>(move |&event, cx| {
|
|
|
|
if let Some(mode_indicator) = handle.upgrade(cx) {
|
|
|
|
match event {
|
|
|
|
VimEvent::ModeChanged { mode } => {
|
2023-08-08 17:08:37 +00:00
|
|
|
mode_indicator.window().update(cx, |cx| {
|
2023-07-27 22:27:36 +00:00
|
|
|
mode_indicator.update(cx, move |mode_indicator, cx| {
|
|
|
|
mode_indicator.set_mode(mode, cx);
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
cx.observe_global::<SettingsStore, _>(move |mode_indicator, cx| {
|
|
|
|
if settings::get::<VimModeSetting>(cx).0 {
|
|
|
|
mode_indicator.mode = cx
|
|
|
|
.has_global::<Vim>()
|
2023-08-17 19:35:32 +00:00
|
|
|
.then(|| cx.global::<Vim>().state().mode);
|
2023-07-27 22:27:36 +00:00
|
|
|
} else {
|
|
|
|
mode_indicator.mode.take();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.detach();
|
|
|
|
|
|
|
|
// Vim doesn't exist in some tests
|
|
|
|
let mode = cx
|
|
|
|
.has_global::<Vim>()
|
2023-07-27 23:14:56 +00:00
|
|
|
.then(|| {
|
|
|
|
let vim = cx.global::<Vim>();
|
2023-08-17 19:35:32 +00:00
|
|
|
vim.enabled.then(|| vim.state().mode)
|
2023-07-27 23:14:56 +00:00
|
|
|
})
|
|
|
|
.flatten();
|
2023-07-27 22:27:36 +00:00
|
|
|
|
|
|
|
Self {
|
|
|
|
mode,
|
|
|
|
_subscription,
|
|
|
|
}
|
2023-07-20 18:32:27 +00:00
|
|
|
}
|
|
|
|
|
2023-07-24 15:37:48 +00:00
|
|
|
pub fn set_mode(&mut self, mode: Mode, cx: &mut ViewContext<Self>) {
|
2023-07-27 22:27:36 +00:00
|
|
|
if self.mode != Some(mode) {
|
|
|
|
self.mode = Some(mode);
|
2023-07-20 18:32:27 +00:00
|
|
|
cx.notify();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Entity for ModeIndicator {
|
|
|
|
type Event = ();
|
|
|
|
}
|
|
|
|
|
|
|
|
impl View for ModeIndicator {
|
|
|
|
fn ui_name() -> &'static str {
|
2023-07-24 15:37:48 +00:00
|
|
|
"ModeIndicatorView"
|
2023-07-20 18:32:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
2023-07-27 22:27:36 +00:00
|
|
|
let Some(mode) = self.mode.as_ref() else {
|
|
|
|
return Empty::new().into_any();
|
|
|
|
};
|
|
|
|
|
2023-07-24 15:37:48 +00:00
|
|
|
let theme = &theme::current(cx).workspace.status_bar;
|
2023-07-27 22:27:36 +00:00
|
|
|
|
2023-07-24 15:37:48 +00:00
|
|
|
// we always choose text to be 12 monospace characters
|
|
|
|
// so that as the mode indicator changes, the rest of the
|
|
|
|
// UI stays still.
|
2023-07-27 22:27:36 +00:00
|
|
|
let text = match mode {
|
2023-07-24 15:37:48 +00:00
|
|
|
Mode::Normal => "-- NORMAL --",
|
|
|
|
Mode::Insert => "-- INSERT --",
|
2023-08-15 14:48:01 +00:00
|
|
|
Mode::Visual => "-- VISUAL --",
|
|
|
|
Mode::VisualLine => "VISUAL LINE",
|
|
|
|
Mode::VisualBlock => "VISUAL BLOCK",
|
2023-07-24 15:37:48 +00:00
|
|
|
};
|
2023-07-25 16:58:44 +00:00
|
|
|
Label::new(text, theme.vim_mode_indicator.text.clone())
|
|
|
|
.contained()
|
|
|
|
.with_style(theme.vim_mode_indicator.container)
|
|
|
|
.into_any()
|
2023-07-20 18:32:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StatusItemView for ModeIndicator {
|
|
|
|
fn set_active_pane_item(
|
|
|
|
&mut self,
|
|
|
|
_active_pane_item: Option<&dyn ItemHandle>,
|
|
|
|
_cx: &mut ViewContext<Self>,
|
|
|
|
) {
|
|
|
|
// nothing to do.
|
|
|
|
}
|
|
|
|
}
|