From 0a2d4b45792c2ff1c5621497385c012be4fe7471 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 7 Nov 2025 17:07:51 +0200 Subject: [PATCH] Hold the brackets lock less --- crates/language/src/buffer.rs | 43 +++++++++++++++++-------- crates/language/src/buffer/row_chunk.rs | 12 ++++--- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 0cb990c31c9476a03b05f6956c641aa5dd3ddb3b..9146d6f33a9487a395b3bb4e30dadbb78d337b68 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -32,7 +32,7 @@ use gpui::{ }; use lsp::{LanguageServerId, NumberOrString}; -use parking_lot::Mutex; +use parking_lot::{Mutex, RawMutex, lock_api::MutexGuard}; use serde::{Deserialize, Serialize}; use serde_json::Value; use settings::WorktreeId; @@ -132,7 +132,7 @@ pub struct Buffer { tree_sitter_data: Arc>, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TreeSitterData { chunks: RowChunks, brackets_by_chunks: Vec>>, @@ -4149,23 +4149,16 @@ impl BufferSnapshot { /// /// The resulting collection is not ordered. fn fetch_bracket_ranges(&self, range: Range) -> Vec { - let mut tree_sitter_data = self.tree_sitter_data.lock(); - if self - .version - .changed_since(&tree_sitter_data.chunks.version()) - { - *tree_sitter_data = TreeSitterData::new(self.text.clone()); - } - + let mut tree_sitter_data = self.latest_tree_sitter_data().clone(); + let mut new_bracket_matches = HashMap::default(); let mut all_bracket_matches = Vec::new(); for chunk in tree_sitter_data .chunks .applicable_chunks(&[self.anchor_before(range.start)..self.anchor_after(range.end)]) - .collect::>() { - let chunk_brackets = &mut tree_sitter_data.brackets_by_chunks[chunk.id]; + let chunk_brackets = tree_sitter_data.brackets_by_chunks.remove(chunk.id); let bracket_matches = match chunk_brackets { - Some(cached_brackets) => cached_brackets.clone(), + Some(cached_brackets) => cached_brackets, None => { let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| { grammar.brackets_config.as_ref().map(|c| &c.query) @@ -4216,16 +4209,38 @@ impl BufferSnapshot { None }) .collect::>(); - *chunk_brackets = Some(new_matches.clone()); + + new_bracket_matches.insert(chunk.id, new_matches.clone()); new_matches } }; all_bracket_matches.extend(bracket_matches); } + let mut latest_tree_sitter_data = self.latest_tree_sitter_data(); + if latest_tree_sitter_data.chunks.version() == &self.version { + for (chunk_id, new_matches) in new_bracket_matches { + let old_chunks = &mut latest_tree_sitter_data.brackets_by_chunks[chunk_id]; + if old_chunks.is_none() { + *old_chunks = Some(new_matches); + } + } + } + all_bracket_matches } + fn latest_tree_sitter_data(&self) -> MutexGuard<'_, RawMutex, TreeSitterData> { + let mut tree_sitter_data = self.tree_sitter_data.lock(); + if self + .version + .changed_since(tree_sitter_data.chunks.version()) + { + *tree_sitter_data = TreeSitterData::new(self.text.clone()); + } + tree_sitter_data + } + pub fn all_bracket_ranges(&self, range: Range) -> Vec { self.fetch_bracket_ranges(range) } diff --git a/crates/language/src/buffer/row_chunk.rs b/crates/language/src/buffer/row_chunk.rs index 5c0b629912d83ff0613f1cdc669f0d14c194052b..c364e8bb685b9dd98f59aef52e0202c7ca014614 100644 --- a/crates/language/src/buffer/row_chunk.rs +++ b/crates/language/src/buffer/row_chunk.rs @@ -1,7 +1,7 @@ //! A row chunk is an exclusive range of rows, [`BufferRow`] within a buffer of a certain version, [`Global`]. //! All but the last chunk are of a constant, given size. -use std::ops::Range; +use std::{ops::Range, sync::Arc}; use clock::Global; use text::OffsetRangeExt as _; @@ -16,9 +16,10 @@ use crate::BufferRow; /// Together, chunks form entire document at a particular version [`Global`]. /// Each chunk is queried for inlays as `(start_row, 0)..(end_exclusive, 0)` via /// +#[derive(Clone)] pub struct RowChunks { pub snapshot: text::BufferSnapshot, - pub chunks: Vec, + pub chunks: Arc<[RowChunk]>, } impl std::fmt::Debug for RowChunks { @@ -42,8 +43,11 @@ impl RowChunks { start: chunk_start, end_exclusive: (chunk_start + max_rows_per_chunk).min(last_row), }) - .collect(); - Self { snapshot, chunks } + .collect::>(); + Self { + snapshot, + chunks: Arc::from(chunks), + } } pub fn version(&self) -> &Global {