diff options
Diffstat (limited to 'support/texlab/src/diagnostics/debouncer.rs')
-rw-r--r-- | support/texlab/src/diagnostics/debouncer.rs | 77 |
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(); + } +} |