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