ZIm/crates/vim/src/mode_indicator.rs
tidely 7bdc99abc1
Fix clippy::redundant_clone lint violations (#36558)
This removes around 900 unnecessary clones, ranging from cloning a few
ints all the way to large data structures and images.

A lot of these were fixed using `cargo clippy --fix --workspace
--all-targets`, however it often breaks other lints and needs to be run
again. This was then followed up with some manual fixing.

I understand this is a large diff, but all the changes are pretty
trivial. Rust is doing some heavy lifting here for us. Once I get it up
to speed with main, I'd appreciate this getting merged rather sooner
than later.

Release Notes:

- N/A
2025-08-20 12:20:13 +02:00

128 lines
4.1 KiB
Rust

use gpui::{Context, Element, Entity, Render, Subscription, WeakEntity, Window, div};
use ui::text_for_keystrokes;
use workspace::{StatusItemView, item::ItemHandle, ui::prelude::*};
use crate::{Vim, VimEvent, VimGlobals};
/// The ModeIndicator displays the current mode in the status bar.
pub struct ModeIndicator {
vim: Option<WeakEntity<Vim>>,
pending_keys: Option<String>,
vim_subscription: Option<Subscription>,
}
impl ModeIndicator {
/// Construct a new mode indicator in this window.
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
cx.observe_pending_input(window, |this: &mut Self, window, cx| {
this.update_pending_keys(window, cx);
cx.notify();
})
.detach();
let handle = cx.entity();
let window_handle = window.window_handle();
cx.observe_new::<Vim>(move |_, window, cx| {
let Some(window) = window else {
return;
};
if window.window_handle() != window_handle {
return;
}
let vim = cx.entity();
handle.update(cx, |_, cx| {
cx.subscribe(&vim, |mode_indicator, vim, event, cx| match event {
VimEvent::Focused => {
mode_indicator.vim_subscription =
Some(cx.observe(&vim, |_, _, cx| cx.notify()));
mode_indicator.vim = Some(vim.downgrade());
}
})
.detach()
})
})
.detach();
Self {
vim: None,
pending_keys: None,
vim_subscription: None,
}
}
fn update_pending_keys(&mut self, window: &mut Window, cx: &App) {
self.pending_keys = window
.pending_input_keystrokes()
.map(|keystrokes| text_for_keystrokes(keystrokes, cx));
}
fn vim(&self) -> Option<Entity<Vim>> {
self.vim.as_ref().and_then(|vim| vim.upgrade())
}
fn current_operators_description(&self, vim: Entity<Vim>, cx: &mut Context<Self>) -> String {
let recording = Vim::globals(cx)
.recording_register
.map(|reg| format!("recording @{reg} "))
.into_iter();
let vim = vim.read(cx);
recording
.chain(
cx.global::<VimGlobals>()
.pre_count
.map(|count| format!("{}", count)),
)
.chain(vim.selected_register.map(|reg| format!("\"{reg}")))
.chain(vim.operator_stack.iter().map(|item| item.status()))
.chain(
cx.global::<VimGlobals>()
.post_count
.map(|count| format!("{}", count)),
)
.collect::<Vec<_>>()
.join("")
}
}
impl Render for ModeIndicator {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let vim = self.vim();
let Some(vim) = vim else {
return div().into_any();
};
let vim_readable = vim.read(cx);
let label = if let Some(label) = vim_readable.status_label.clone() {
label
} else {
let mode = if vim_readable.temp_mode {
format!("(insert) {}", vim_readable.mode)
} else {
vim_readable.mode.to_string()
};
let current_operators_description = self.current_operators_description(vim.clone(), cx);
let pending = self
.pending_keys
.as_ref()
.unwrap_or(&current_operators_description);
format!("{} -- {} --", pending, mode).into()
};
Label::new(label)
.size(LabelSize::Small)
.line_height_style(LineHeightStyle::UiLabel)
.into_any_element()
}
}
impl StatusItemView for ModeIndicator {
fn set_active_pane_item(
&mut self,
_active_pane_item: Option<&dyn ItemHandle>,
_window: &mut Window,
_cx: &mut Context<Self>,
) {
}
}