summaryrefslogtreecommitdiff
path: root/support/texlab/src/diagnostics/debouncer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/diagnostics/debouncer.rs')
-rw-r--r--support/texlab/src/diagnostics/debouncer.rs77
1 files changed, 77 insertions, 0 deletions
diff --git a/support/texlab/src/diagnostics/debouncer.rs b/support/texlab/src/diagnostics/debouncer.rs
new file mode 100644
index 0000000000..46bea80176
--- /dev/null
+++ b/support/texlab/src/diagnostics/debouncer.rs
@@ -0,0 +1,77 @@
+use std::{
+ sync::Arc,
+ thread::{self, JoinHandle},
+ time::{Duration, Instant},
+};
+
+use chashmap::CHashMap;
+use crossbeam_channel::Sender;
+
+use crate::{Document, ServerContext, Uri, Workspace};
+
+pub enum DiagnosticsMessage {
+ Analyze {
+ workspace: Arc<dyn Workspace>,
+ document: Arc<Document>,
+ },
+ Shutdown,
+}
+
+pub struct DiagnosticsDebouncer {
+ pub sender: Sender<DiagnosticsMessage>,
+ handle: Option<JoinHandle<()>>,
+}
+
+impl DiagnosticsDebouncer {
+ pub fn launch<A>(context: Arc<ServerContext>, action: A) -> Self
+ where
+ A: Fn(Arc<dyn Workspace>, Arc<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<CHashMap<Arc<Uri>, Instant>> = Arc::default();
+ while let Ok(DiagnosticsMessage::Analyze {
+ workspace,
+ document,
+ }) = receiver.recv()
+ {
+ let delay = {
+ context
+ .options
+ .read()
+ .unwrap()
+ .diagnostics_delay
+ .unwrap_or(300)
+ };
+
+ if let Some(time) = last_task_time_by_uri.get(&document.uri) {
+ if time.elapsed().as_millis() < delay as u128 {
+ 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();
+ }
+}