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}