1use crate::EditorSettings;
2use gpui::Context;
3use settings::Settings;
4use settings::SettingsStore;
5use smol::Timer;
6use std::time::Duration;
7
8pub struct BlinkManager {
9 blink_interval: Duration,
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 Context<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 blink_epoch: 0,
27 blinking_paused: false,
28 visible: true,
29 enabled: false,
30 }
31 }
32
33 fn next_blink_epoch(&mut self) -> usize {
34 self.blink_epoch += 1;
35 self.blink_epoch
36 }
37
38 pub fn pause_blinking(&mut self, cx: &mut Context<Self>) {
39 self.show_cursor(cx);
40
41 let epoch = self.next_blink_epoch();
42 let interval = self.blink_interval;
43 cx.spawn(async move |this, cx| {
44 Timer::after(interval).await;
45 this.update(cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
46 })
47 .detach();
48 }
49
50 fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut Context<Self>) {
51 if epoch == self.blink_epoch {
52 self.blinking_paused = false;
53 self.blink_cursors(epoch, cx);
54 }
55 }
56
57 fn blink_cursors(&mut self, epoch: usize, cx: &mut Context<Self>) {
58 if EditorSettings::get_global(cx).cursor_blink {
59 if epoch == self.blink_epoch && self.enabled && !self.blinking_paused {
60 self.visible = !self.visible;
61 cx.notify();
62
63 let epoch = self.next_blink_epoch();
64 let interval = self.blink_interval;
65 cx.spawn(async move |this, cx| {
66 Timer::after(interval).await;
67 if let Some(this) = this.upgrade() {
68 this.update(cx, |this, cx| this.blink_cursors(epoch, cx))
69 .ok();
70 }
71 })
72 .detach();
73 }
74 } else {
75 self.show_cursor(cx);
76 }
77 }
78
79 pub fn show_cursor(&mut self, cx: &mut Context<BlinkManager>) {
80 if !self.visible {
81 self.visible = true;
82 cx.notify();
83 }
84 }
85
86 pub fn enable(&mut self, cx: &mut Context<Self>) {
87 if self.enabled {
88 return;
89 }
90
91 self.enabled = true;
92 // Set cursors as invisible and start blinking: this causes cursors
93 // to be visible during the next render.
94 self.visible = false;
95 self.blink_cursors(self.blink_epoch, cx);
96 }
97
98 pub fn disable(&mut self, _cx: &mut Context<Self>) {
99 self.visible = false;
100 self.enabled = false;
101 }
102
103 pub fn visible(&self) -> bool {
104 self.visible
105 }
106}