use gpui::Context; use settings::SettingsStore; use std::time::Duration; use ui::App; pub struct BlinkManager { blink_interval: Duration, blink_epoch: usize, /// Whether the blinking is paused. blinking_paused: bool, /// Whether the cursor should be visibly rendered or not. visible: bool, /// Whether the blinking currently enabled. enabled: bool, /// Whether the blinking is enabled in the settings. blink_enabled_in_settings: fn(&App) -> bool, } impl BlinkManager { pub fn new( blink_interval: Duration, blink_enabled_in_settings: fn(&App) -> bool, cx: &mut Context, ) -> Self { // Make sure we blink the cursors if the setting is re-enabled cx.observe_global::(move |this, cx| { this.blink_cursors(this.blink_epoch, cx) }) .detach(); Self { blink_interval, blink_epoch: 0, blinking_paused: false, visible: true, enabled: false, blink_enabled_in_settings, } } fn next_blink_epoch(&mut self) -> usize { self.blink_epoch += 1; self.blink_epoch } pub fn pause_blinking(&mut self, cx: &mut Context) { self.show_cursor(cx); let epoch = self.next_blink_epoch(); let interval = Duration::from_millis(500); cx.spawn(async move |this, cx| { cx.background_executor().timer(interval).await; this.update(cx, |this, cx| this.resume_cursor_blinking(epoch, cx)) }) .detach(); } fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut Context) { if epoch == self.blink_epoch { self.blinking_paused = false; self.blink_cursors(epoch, cx); } } fn blink_cursors(&mut self, epoch: usize, cx: &mut Context) { if (self.blink_enabled_in_settings)(cx) { if epoch == self.blink_epoch && self.enabled && !self.blinking_paused { self.visible = !self.visible; cx.notify(); let epoch = self.next_blink_epoch(); let interval = self.blink_interval; cx.spawn(async move |this, cx| { cx.background_executor().timer(interval).await; if let Some(this) = this.upgrade() { this.update(cx, |this, cx| this.blink_cursors(epoch, cx)); } }) .detach(); } } else { self.show_cursor(cx); } } pub fn show_cursor(&mut self, cx: &mut Context) { if !self.visible { self.visible = true; cx.notify(); } } /// Enable the blinking of the cursor. pub fn enable(&mut self, cx: &mut Context) { if self.enabled { return; } self.enabled = true; // Set cursors as invisible and start blinking: this causes cursors // to be visible during the next render. self.visible = false; self.blink_cursors(self.blink_epoch, cx); } /// Disable the blinking of the cursor. pub fn disable(&mut self, _cx: &mut Context) { self.visible = false; self.enabled = false; } pub fn visible(&self) -> bool { self.visible } }