blink_manager.rs

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