diff --git a/crates/language/src/syntax_map.rs b/crates/language/src/syntax_map.rs index bd24424679f3e6cb02303c91e0d86db335cd0a26..c5931c474d2962fc7ceb66954f2f00d3bf14b4f8 100644 --- a/crates/language/src/syntax_map.rs +++ b/crates/language/src/syntax_map.rs @@ -13,7 +13,7 @@ use std::{ collections::BinaryHeap, fmt, iter, ops::{ControlFlow, Deref, DerefMut, Range}, - sync::Arc, + sync::{Arc, LazyLock}, time::{Duration, Instant}, }; use streaming_iterator::StreamingIterator; @@ -40,6 +40,27 @@ pub struct SyntaxSnapshot { update_count: usize, } +// Dropping deep treesitter Trees can be quite slow due to deallocating lots of memory. +// To avoid blocking the main thread, we offload the drop operation to a background thread. +impl Drop for SyntaxSnapshot { + fn drop(&mut self) { + static DROP_TX: LazyLock>> = + LazyLock::new(|| { + let (tx, rx) = std::sync::mpsc::channel(); + std::thread::Builder::new() + .name("SyntaxSnapshot::drop".into()) + .spawn(move || while let Ok(_) = rx.recv() {}) + .expect("failed to spawn drop thread"); + tx + }); + // This does allocate a new Arc, but it's cheap and avoids blocking the main thread without needing to use an `Option` or `MaybeUninit`. + let _ = DROP_TX.send(std::mem::replace( + &mut self.layers, + SumTree::from_summary(Default::default()), + )); + } +} + #[derive(Default)] pub struct SyntaxMapCaptures<'a> { layers: Vec>,