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