1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
use std::{
sync::Arc,
thread::{self, JoinHandle},
time::{Duration, Instant},
};
use crossbeam_channel::Sender;
use dashmap::DashMap;
use lsp_types::Url;
use crate::{Document, Workspace};
pub enum DiagnosticsMessage {
Analyze {
workspace: Workspace,
document: Document,
},
Shutdown,
}
pub struct DiagnosticsDebouncer {
pub sender: Sender<DiagnosticsMessage>,
handle: Option<JoinHandle<()>>,
}
impl DiagnosticsDebouncer {
pub fn launch<A>(action: A) -> Self
where
A: Fn(Workspace, Document) + Send + Clone + 'static,
{
let (sender, receiver) = crossbeam_channel::unbounded();
let handle = thread::spawn(move || {
let pool = threadpool::Builder::new().build();
let last_task_time_by_uri: Arc<DashMap<Arc<Url>, Instant>> = Arc::default();
while let Ok(DiagnosticsMessage::Analyze {
workspace,
document,
}) = receiver.recv()
{
let delay = workspace
.environment
.options
.diagnostics_delay
.unwrap_or(300);
if let Some(time) = last_task_time_by_uri.get(&document.uri) {
if time.elapsed().as_millis() < u128::from(delay) {
continue;
}
}
let last_task_time_by_uri = Arc::clone(&last_task_time_by_uri);
let action = action.clone();
pool.execute(move || {
thread::sleep(Duration::from_millis(delay));
last_task_time_by_uri.insert(Arc::clone(&document.uri), Instant::now());
action(workspace, document);
});
}
});
Self {
sender,
handle: Some(handle),
}
}
}
impl Drop for DiagnosticsDebouncer {
fn drop(&mut self) {
self.sender.send(DiagnosticsMessage::Shutdown).unwrap();
self.handle.take().unwrap().join().unwrap();
}
}
|