From 746ecb082d3d88eabc9bfb74695e4af77b1aa85e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 28 Feb 2026 12:53:06 +0100 Subject: [PATCH] buffer_diff: Do not block on parsing in `set_snapshot_with_secondary_inner` (#50385) Release Notes: - N/A *or* Added/Fixed/Improved ... --- crates/buffer_diff/src/buffer_diff.rs | 2 ++ .../src/edit_prediction_context.rs | 14 ++++++-------- crates/editor/src/inlays.rs | 6 ++++-- crates/editor/src/inlays/inlay_hints.rs | 2 +- crates/language/src/buffer.rs | 14 ++++++++++++-- crates/language_tools/src/highlights_tree_view.rs | 8 +++----- crates/rope/src/rope.rs | 13 +++++++++---- 7 files changed, 37 insertions(+), 22 deletions(-) diff --git a/crates/buffer_diff/src/buffer_diff.rs b/crates/buffer_diff/src/buffer_diff.rs index 2c9a68d5526f2cb0f03bc3da7ab611233091b143..8e61a9b633930655e296433711013645ea873dfd 100644 --- a/crates/buffer_diff/src/buffer_diff.rs +++ b/crates/buffer_diff/src/buffer_diff.rs @@ -1753,6 +1753,7 @@ impl BufferDiff { let should_compare_hunks = update.base_text_edits.is_some() || !base_text_changed; let parsing_idle = if let Some(diff) = update.base_text_edits { state.base_text.update(cx, |base_text, cx| { + base_text.set_sync_parse_timeout(None); base_text.set_capability(Capability::ReadWrite, cx); base_text.apply_diff(diff, cx); base_text.set_capability(Capability::ReadOnly, cx); @@ -1760,6 +1761,7 @@ impl BufferDiff { }) } else if update.base_text_changed { state.base_text.update(cx, |base_text, cx| { + base_text.set_sync_parse_timeout(None); base_text.set_capability(Capability::ReadWrite, cx); base_text.set_text(new_state.base_text.clone(), cx); base_text.set_capability(Capability::ReadOnly, cx); diff --git a/crates/edit_prediction_context/src/edit_prediction_context.rs b/crates/edit_prediction_context/src/edit_prediction_context.rs index b93fef49296e493b4f06e93e8d855d6a8e111e97..a44ff8b2e3e873c23c2eaa914298a4d50aee3bdc 100644 --- a/crates/edit_prediction_context/src/edit_prediction_context.rs +++ b/crates/edit_prediction_context/src/edit_prediction_context.rs @@ -644,14 +644,12 @@ fn identifiers_for_position( let outer_range = ranges.first().map_or(0, |r| r.start)..ranges.last().map_or(buffer.len(), |r| r.end); - let mut captures = buffer - .syntax - .captures(outer_range.clone(), &buffer.text, |grammar| { - grammar - .highlights_config - .as_ref() - .map(|config| &config.query) - }); + let mut captures = buffer.captures(outer_range.clone(), |grammar| { + grammar + .highlights_config + .as_ref() + .map(|config| &config.query) + }); for range in ranges { captures.set_byte_range(range.start..outer_range.end); diff --git a/crates/editor/src/inlays.rs b/crates/editor/src/inlays.rs index a240837918340f3a2540491a175d13e90de2931e..8c46e797cada703c9101fd91e670cbdd4ea713ac 100644 --- a/crates/editor/src/inlays.rs +++ b/crates/editor/src/inlays.rs @@ -58,10 +58,12 @@ pub enum InlayContent { impl Inlay { pub fn hint(id: InlayId, position: Anchor, hint: &InlayHint) -> Self { let mut text = hint.text(); - if hint.padding_right && text.reversed_chars_at(text.len()).next() != Some(' ') { + let needs_right_padding = hint.padding_right && !text.ends_with(" "); + let needs_left_padding = hint.padding_left && !text.starts_with(" "); + if needs_right_padding { text.push(" "); } - if hint.padding_left && text.chars_at(0).next() != Some(' ') { + if needs_left_padding { text.push_front(" "); } Self { diff --git a/crates/editor/src/inlays/inlay_hints.rs b/crates/editor/src/inlays/inlay_hints.rs index 23c97ced906844c1ac6c8fa5ce6932631284384a..d7a116065101dcc5070a7280ba7c3424e74685fe 100644 --- a/crates/editor/src/inlays/inlay_hints.rs +++ b/crates/editor/src/inlays/inlay_hints.rs @@ -369,7 +369,7 @@ impl Editor { if invalidate_cache.should_invalidate() { if invalidate_hints_for_buffers.is_empty() { inlay_hints.clear(); - } else if invalidate_cache.should_invalidate() { + } else { inlay_hints.clear_for_buffers( &invalidate_hints_for_buffers, Self::visible_inlay_hints(self.display_map.read(cx)), diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 1449052983a49a539201360ec48dd37c04a4ccae..eb9bb0827a7be9f4a725246c6d38777e340eee2c 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -187,7 +187,7 @@ struct BufferBranchState { /// state of a buffer. pub struct BufferSnapshot { pub text: text::BufferSnapshot, - pub syntax: SyntaxSnapshot, + pub(crate) syntax: SyntaxSnapshot, tree_sitter_data: Arc, diagnostics: TreeMap, remote_selections: TreeMap, @@ -1776,7 +1776,9 @@ impl Buffer { self.syntax_map.lock().contains_unknown_injections() } - #[cfg(any(test, feature = "test-support"))] + /// Sets the sync parse timeout for this buffer. + /// + /// Setting this to `None` disables sync parsing entirely. pub fn set_sync_parse_timeout(&mut self, timeout: Option) { self.sync_parse_timeout = timeout; } @@ -3706,6 +3708,14 @@ impl BufferSnapshot { None } + pub fn captures( + &self, + range: Range, + query: fn(&Grammar) -> Option<&tree_sitter::Query>, + ) -> SyntaxMapCaptures<'_> { + self.syntax.captures(range, &self.text, query) + } + #[ztracing::instrument(skip_all)] fn get_highlights(&self, range: Range) -> (SyntaxMapCaptures<'_>, Vec) { let captures = self.syntax.captures(range, &self.text, |grammar| { diff --git a/crates/language_tools/src/highlights_tree_view.rs b/crates/language_tools/src/highlights_tree_view.rs index 9796c1c07375956184bdd28fbd8f5bb52bff2a32..fb92e21ab33eb3b6a3cd498a6ffbdd764947ea9e 100644 --- a/crates/language_tools/src/highlights_tree_view.rs +++ b/crates/language_tools/src/highlights_tree_view.rs @@ -397,11 +397,9 @@ impl HighlightsTreeView { let end_offset = excerpt_range.context.end.to_offset(buffer_snapshot); let range = start_offset..end_offset; - let captures = buffer_snapshot - .syntax - .captures(range, buffer_snapshot, |grammar| { - grammar.highlights_config.as_ref().map(|c| &c.query) - }); + let captures = buffer_snapshot.captures(range, |grammar| { + grammar.highlights_config.as_ref().map(|c| &c.query) + }); let grammars: Vec<_> = captures.grammars().to_vec(); let highlight_maps: Vec<_> = grammars.iter().map(|g| g.highlight_map()).collect(); diff --git a/crates/rope/src/rope.rs b/crates/rope/src/rope.rs index 8b5ea03c66945519c955a7d43324b8f5e4b32d1b..9d54f1ba5302291e20289dcdf2c71cceb2e6e349 100644 --- a/crates/rope/src/rope.rs +++ b/crates/rope/src/rope.rs @@ -553,7 +553,10 @@ impl Rope { return false; } let mut remaining = pattern; - for chunk in self.chunks_in_range(0..pattern.len()) { + for chunk in self.chunks_in_range(0..self.len()) { + let Some(chunk) = chunk.get(..remaining.len().min(chunk.len())) else { + return false; + }; if remaining.starts_with(chunk) { remaining = &remaining[chunk.len()..]; if remaining.is_empty() { @@ -567,12 +570,14 @@ impl Rope { } pub fn ends_with(&self, pattern: &str) -> bool { - let len = self.len(); - if pattern.len() > len { + if pattern.len() > self.len() { return false; } let mut remaining = pattern; - for chunk in self.reversed_chunks_in_range(len - pattern.len()..len) { + for chunk in self.reversed_chunks_in_range(0..self.len()) { + let Some(chunk) = chunk.get(chunk.len() - remaining.len().min(chunk.len())..) else { + return false; + }; if remaining.ends_with(chunk) { remaining = &remaining[..remaining.len() - chunk.len()]; if remaining.is_empty() {