blink_manager.rs

  1use gpui::Context;
  2use settings::SettingsStore;
  3use smol::Timer;
  4use std::time::Duration;
  5use ui::App;
  6
  7pub struct BlinkManager {
  8    blink_interval: Duration,
  9    blink_epoch: usize,
 10    /// Whether the blinking is paused.
 11    blinking_paused: bool,
 12    /// Whether the cursor should be visibly rendered or not.
 13    visible: bool,
 14    /// Whether the blinking currently enabled.
 15    enabled: bool,
 16    /// Whether the blinking is enabled in the settings.
 17    blink_enabled_in_settings: fn(&App) -> bool,
 18}
 19
 20impl BlinkManager {
 21    pub fn new(
 22        blink_interval: Duration,
 23        blink_enabled_in_settings: fn(&App) -> bool,
 24        cx: &mut Context<Self>,
 25    ) -> Self {
 26        // Make sure we blink the cursors if the setting is re-enabled
 27        cx.observe_global::<SettingsStore>(move |this, cx| {
 28            this.blink_cursors(this.blink_epoch, cx)
 29        })
 30        .detach();
 31
 32        Self {
 33            blink_interval,
 34            blink_epoch: 0,
 35            blinking_paused: false,
 36            visible: true,
 37            enabled: false,
 38            blink_enabled_in_settings,
 39        }
 40    }
 41
 42    fn next_blink_epoch(&mut self) -> usize {
 43        self.blink_epoch += 1;
 44        self.blink_epoch
 45    }
 46
 47    pub fn pause_blinking(&mut self, cx: &mut Context<Self>) {
 48        self.show_cursor(cx);
 49
 50        let epoch = self.next_blink_epoch();
 51        let interval = self.blink_interval;
 52        cx.spawn(async move |this, cx| {
 53            Timer::after(interval).await;
 54            this.update(cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
 55        })
 56        .detach();
 57    }
 58
 59    fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut Context<Self>) {
 60        if epoch == self.blink_epoch {
 61            self.blinking_paused = false;
 62            self.blink_cursors(epoch, cx);
 63        }
 64    }
 65
 66    fn blink_cursors(&mut self, epoch: usize, cx: &mut Context<Self>) {
 67        if (self.blink_enabled_in_settings)(cx) {
 68            if epoch == self.blink_epoch && self.enabled && !self.blinking_paused {
 69                self.visible = !self.visible;
 70                cx.notify();
 71
 72                let epoch = self.next_blink_epoch();
 73                let interval = self.blink_interval;
 74                cx.spawn(async move |this, cx| {
 75                    Timer::after(interval).await;
 76                    if let Some(this) = this.upgrade() {
 77                        this.update(cx, |this, cx| this.blink_cursors(epoch, cx))
 78                            .ok();
 79                    }
 80                })
 81                .detach();
 82            }
 83        } else {
 84            self.show_cursor(cx);
 85        }
 86    }
 87
 88    pub fn show_cursor(&mut self, cx: &mut Context<BlinkManager>) {
 89        if !self.visible {
 90            self.visible = true;
 91            cx.notify();
 92        }
 93    }
 94
 95    /// Enable the blinking of the cursor.
 96    pub fn enable(&mut self, cx: &mut Context<Self>) {
 97        if self.enabled {
 98            return;
 99        }
100
101        self.enabled = true;
102        // Set cursors as invisible and start blinking: this causes cursors
103        // to be visible during the next render.
104        self.visible = false;
105        self.blink_cursors(self.blink_epoch, cx);
106    }
107
108    /// Disable the blinking of the cursor.
109    pub fn disable(&mut self, _cx: &mut Context<Self>) {
110        self.visible = false;
111        self.enabled = false;
112    }
113
114    pub fn visible(&self) -> bool {
115        self.visible
116    }
117}