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 if !self.visible {
41 self.visible = true;
42 cx.notify();
43 }
44
45 let epoch = self.next_blink_epoch();
46 let interval = self.blink_interval;
47 cx.spawn(|this, mut cx| {
48 let this = this.downgrade();
49 async move {
50 Timer::after(interval).await;
51 if let Some(this) = this.upgrade(&cx) {
52 this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
53 }
54 }
55 })
56 .detach();
57 }
58
59 fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ModelContext<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 ModelContext<Self>) {
67 if settings::get::<EditorSettings>(cx).cursor_blink {
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(|this, mut cx| {
75 let this = this.downgrade();
76 async move {
77 Timer::after(interval).await;
78 if let Some(this) = this.upgrade(&cx) {
79 this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
80 }
81 }
82 })
83 .detach();
84 }
85 } else if !self.visible {
86 self.visible = true;
87 cx.notify();
88 }
89 }
90
91 pub fn enable(&mut self, cx: &mut ModelContext<Self>) {
92 self.enabled = true;
93 // Set cursors as invisible and start blinking: this causes cursors
94 // to be visible during the next render.
95 self.visible = false;
96 self.blink_cursors(self.blink_epoch, cx);
97 }
98
99 pub fn disable(&mut self, _cx: &mut ModelContext<Self>) {
100 self.enabled = false;
101 }
102
103 pub fn visible(&self) -> bool {
104 self.visible
105 }
106}
107
108impl Entity for BlinkManager {
109 type Event = ();
110}