From 98132978925c7a2363d8096a9246b808d64a0c90 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Sun, 23 Jun 2024 22:20:10 -0700 Subject: [PATCH] Combine multiple buffer update count fields into one (#13449) Buffers carry several pieces of state besides their text: syntax tree, diagnostics, git diff, and file data. Previously, the buffer maintained a separate integer version number for each of these four pieces of state, incrementing it every time that piece of state is updated. This is used by MultiBuffers to detect when they need to update excerpts. Previously, for a given buffer, these four version numbers were stored on the buffer itself, on every snapshot of the buffer, in any multi-buffer that referenced that buffer, **and** on snapshots of that multi-buffer. But the only use for the version numbers was reduced down to a single boolean predicate: whether or not the buffer's state has changed. In this PR, I've combined those 4 version numbers into one. I've called it `non_text_state_update_count` because it tracks all state updates outside of the text itself. This removes a bunch of unnecessary code, and reduces the size of buffer snapshots and multi-buffer snapshots. Release Notes: - N/A --- crates/editor/src/display_map/inlay_map.rs | 7 +- crates/language/src/buffer.rs | 98 +++++----------------- crates/multi_buffer/src/multi_buffer.rs | 82 ++++-------------- 3 files changed, 37 insertions(+), 150 deletions(-) diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs index ad5cc84ef78b1316e9648935e358f08f392412ea..82565e56b6cab4aa3c80fc385cce69b35aaa8771 100644 --- a/crates/editor/src/display_map/inlay_map.rs +++ b/crates/editor/src/display_map/inlay_map.rs @@ -462,11 +462,8 @@ impl InlayMap { if buffer_edits.is_empty() { if snapshot.buffer.edit_count() != buffer_snapshot.edit_count() - || snapshot.buffer.parse_count() != buffer_snapshot.parse_count() - || snapshot.buffer.diagnostics_update_count() - != buffer_snapshot.diagnostics_update_count() - || snapshot.buffer.git_diff_update_count() - != buffer_snapshot.git_diff_update_count() + || snapshot.buffer.non_text_state_update_count() + != buffer_snapshot.non_text_state_update_count() || snapshot.buffer.trailing_excerpt_update_count() != buffer_snapshot.trailing_excerpt_update_count() { diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index eda38f8a76f4a76cbc8cd6b32a1fab47c62d5b29..40b8ef6b5ed3441b1dd4e5b61c4c586339f21538 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -103,14 +103,10 @@ pub struct Buffer { sync_parse_timeout: Duration, syntax_map: Mutex, parsing_in_background: bool, - parse_count: usize, + non_text_state_update_count: usize, diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>, remote_selections: TreeMap, - selections_update_count: usize, - diagnostics_update_count: usize, diagnostics_timestamp: clock::Lamport, - file_update_count: usize, - git_diff_update_count: usize, completion_triggers: Vec, completion_triggers_timestamp: clock::Lamport, deferred_ops: OperationQueue, @@ -127,13 +123,9 @@ pub struct BufferSnapshot { pub(crate) syntax: SyntaxSnapshot, file: Option>, diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>, - diagnostics_update_count: usize, - file_update_count: usize, - git_diff_update_count: usize, remote_selections: TreeMap, - selections_update_count: usize, language: Option>, - parse_count: usize, + non_text_state_update_count: usize, } /// The kind and amount of indentation in a particular line. For now, @@ -711,18 +703,14 @@ impl Buffer { capability, syntax_map: Mutex::new(SyntaxMap::new()), parsing_in_background: false, - parse_count: 0, + non_text_state_update_count: 0, sync_parse_timeout: Duration::from_millis(1), autoindent_requests: Default::default(), pending_autoindent: Default::default(), language: None, remote_selections: Default::default(), - selections_update_count: 0, diagnostics: Default::default(), - diagnostics_update_count: 0, diagnostics_timestamp: Default::default(), - file_update_count: 0, - git_diff_update_count: 0, completion_triggers: Default::default(), completion_triggers_timestamp: Default::default(), deferred_ops: OperationQueue::new(), @@ -745,12 +733,8 @@ impl Buffer { file: self.file.clone(), remote_selections: self.remote_selections.clone(), diagnostics: self.diagnostics.clone(), - diagnostics_update_count: self.diagnostics_update_count, - file_update_count: self.file_update_count, - git_diff_update_count: self.git_diff_update_count, language: self.language.clone(), - parse_count: self.parse_count, - selections_update_count: self.selections_update_count, + non_text_state_update_count: self.non_text_state_update_count, } } @@ -782,7 +766,7 @@ impl Buffer { /// Assign a language to the buffer. pub fn set_language(&mut self, language: Option>, cx: &mut ModelContext) { - self.parse_count += 1; + self.non_text_state_update_count += 1; self.syntax_map.lock().clear(); self.language = language; self.reparse(cx); @@ -915,7 +899,7 @@ impl Buffer { self.file = Some(new_file); if file_changed { - self.file_update_count += 1; + self.non_text_state_update_count += 1; cx.emit(Event::FileHandleChanged); cx.notify(); } @@ -969,7 +953,7 @@ impl Buffer { let buffer_diff = diff.await; this.update(&mut cx, |this, cx| { this.git_diff = buffer_diff; - this.git_diff_update_count += 1; + this.non_text_state_update_count += 1; cx.emit(Event::DiffUpdated); }) .ok(); @@ -992,29 +976,10 @@ impl Buffer { .or_else(|| self.language.clone()) } - /// The number of times the buffer was parsed. - pub fn parse_count(&self) -> usize { - self.parse_count - } - - /// The number of times selections were updated. - pub fn selections_update_count(&self) -> usize { - self.selections_update_count - } - - /// The number of times diagnostics were updated. - pub fn diagnostics_update_count(&self) -> usize { - self.diagnostics_update_count - } - - /// The number of times the underlying file was updated. - pub fn file_update_count(&self) -> usize { - self.file_update_count - } - - /// The number of times the git diff status was updated. - pub fn git_diff_update_count(&self) -> usize { - self.git_diff_update_count + /// An integer version number that accounts for all updates besides + /// the buffer's text itself (which is versioned via a version vector). + pub fn non_text_state_update_count(&self) -> usize { + self.non_text_state_update_count } /// Whether the buffer is being parsed in the background. @@ -1124,7 +1089,7 @@ impl Buffer { } fn did_finish_parsing(&mut self, syntax_snapshot: SyntaxSnapshot, cx: &mut ModelContext) { - self.parse_count += 1; + self.non_text_state_update_count += 1; self.syntax_map.lock().did_parse(syntax_snapshot); self.request_autoindent(cx); cx.emit(Event::Reparsed); @@ -1701,7 +1666,7 @@ impl Buffer { }, cx, ); - self.selections_update_count += 1; + self.non_text_state_update_count += 1; cx.notify(); } @@ -1973,7 +1938,7 @@ impl Buffer { }, ); self.text.lamport_clock.observe(lamport_timestamp); - self.selections_update_count += 1; + self.non_text_state_update_count += 1; } Operation::UpdateCompletionTriggers { triggers, @@ -2005,7 +1970,7 @@ impl Buffer { }; } self.diagnostics_timestamp = lamport_timestamp; - self.diagnostics_update_count += 1; + self.non_text_state_update_count += 1; self.text.lamport_clock.observe(lamport_timestamp); cx.notify(); cx.emit(Event::DiagnosticsUpdated); @@ -3523,19 +3488,10 @@ impl BufferSnapshot { .flat_map(move |(_, set)| set.group(group_id, self)) } - /// The number of times diagnostics were updated. - pub fn diagnostics_update_count(&self) -> usize { - self.diagnostics_update_count - } - - /// The number of times the buffer was parsed. - pub fn parse_count(&self) -> usize { - self.parse_count - } - - /// The number of times selections were updated. - pub fn selections_update_count(&self) -> usize { - self.selections_update_count + /// An integer version number that accounts for all updates besides + /// the buffer's text itself (which is versioned via a version vector). + pub fn non_text_state_update_count(&self) -> usize { + self.non_text_state_update_count } /// Returns a snapshot of underlying file. @@ -3555,16 +3511,6 @@ impl BufferSnapshot { None } } - - /// The number of times the underlying file was updated. - pub fn file_update_count(&self) -> usize { - self.file_update_count - } - - /// The number of times the git diff status was updated. - pub fn git_diff_update_count(&self) -> usize { - self.git_diff_update_count - } } fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize { @@ -3596,12 +3542,8 @@ impl Clone for BufferSnapshot { file: self.file.clone(), remote_selections: self.remote_selections.clone(), diagnostics: self.diagnostics.clone(), - selections_update_count: self.selections_update_count, - diagnostics_update_count: self.diagnostics_update_count, - file_update_count: self.file_update_count, - git_diff_update_count: self.git_diff_update_count, language: self.language.clone(), - parse_count: self.parse_count, + non_text_state_update_count: self.non_text_state_update_count, } } } diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 19f0814207eb0b6f6e3d0087d7c349394d379c3d..663dad51bfa5ec3731b4c98963530a8c86a2d700 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -152,11 +152,7 @@ pub trait ToPointUtf16: 'static + fmt::Debug { struct BufferState { buffer: Model, last_version: clock::Global, - last_parse_count: usize, - last_selections_update_count: usize, - last_diagnostics_update_count: usize, - last_file_update_count: usize, - last_git_diff_update_count: usize, + last_non_text_state_update_count: usize, excerpts: Vec, _subscriptions: [gpui::Subscription; 2], } @@ -167,10 +163,8 @@ pub struct MultiBufferSnapshot { singleton: bool, excerpts: SumTree, excerpt_ids: SumTree, - parse_count: usize, - diagnostics_update_count: usize, trailing_excerpt_update_count: usize, - git_diff_update_count: usize, + non_text_state_update_count: usize, edit_count: usize, is_dirty: bool, has_conflict: bool, @@ -396,11 +390,7 @@ impl MultiBuffer { BufferState { buffer: buffer_state.buffer.clone(), last_version: buffer_state.last_version.clone(), - last_parse_count: buffer_state.last_parse_count, - last_selections_update_count: buffer_state.last_selections_update_count, - last_diagnostics_update_count: buffer_state.last_diagnostics_update_count, - last_file_update_count: buffer_state.last_file_update_count, - last_git_diff_update_count: buffer_state.last_git_diff_update_count, + last_non_text_state_update_count: buffer_state.last_non_text_state_update_count, excerpts: buffer_state.excerpts.clone(), _subscriptions: [ new_cx.observe(&buffer_state.buffer, |_, _, cx| cx.notify()), @@ -1244,11 +1234,7 @@ impl MultiBuffer { let mut buffers = self.buffers.borrow_mut(); let buffer_state = buffers.entry(buffer_id).or_insert_with(|| BufferState { last_version: buffer_snapshot.version().clone(), - last_parse_count: buffer_snapshot.parse_count(), - last_selections_update_count: buffer_snapshot.selections_update_count(), - last_diagnostics_update_count: buffer_snapshot.diagnostics_update_count(), - last_file_update_count: buffer_snapshot.file_update_count(), - last_git_diff_update_count: buffer_snapshot.git_diff_update_count(), + last_non_text_state_update_count: buffer_snapshot.non_text_state_update_count(), excerpts: Default::default(), _subscriptions: [ cx.observe(&buffer, |_, _, cx| cx.notify()), @@ -1823,9 +1809,7 @@ impl MultiBuffer { fn sync(&self, cx: &AppContext) { let mut snapshot = self.snapshot.borrow_mut(); let mut excerpts_to_edit = Vec::new(); - let mut reparsed = false; - let mut diagnostics_updated = false; - let mut git_diff_updated = false; + let mut non_text_state_updated = false; let mut is_dirty = false; let mut has_conflict = false; let mut edited = false; @@ -1833,34 +1817,14 @@ impl MultiBuffer { for buffer_state in buffers.values_mut() { let buffer = buffer_state.buffer.read(cx); let version = buffer.version(); - let parse_count = buffer.parse_count(); - let selections_update_count = buffer.selections_update_count(); - let diagnostics_update_count = buffer.diagnostics_update_count(); - let file_update_count = buffer.file_update_count(); - let git_diff_update_count = buffer.git_diff_update_count(); + let non_text_state_update_count = buffer.non_text_state_update_count(); let buffer_edited = version.changed_since(&buffer_state.last_version); - let buffer_reparsed = parse_count > buffer_state.last_parse_count; - let buffer_selections_updated = - selections_update_count > buffer_state.last_selections_update_count; - let buffer_diagnostics_updated = - diagnostics_update_count > buffer_state.last_diagnostics_update_count; - let buffer_file_updated = file_update_count > buffer_state.last_file_update_count; - let buffer_git_diff_updated = - git_diff_update_count > buffer_state.last_git_diff_update_count; - if buffer_edited - || buffer_reparsed - || buffer_selections_updated - || buffer_diagnostics_updated - || buffer_file_updated - || buffer_git_diff_updated - { + let buffer_non_text_state_updated = + non_text_state_update_count > buffer_state.last_non_text_state_update_count; + if buffer_edited || buffer_non_text_state_updated { buffer_state.last_version = version; - buffer_state.last_parse_count = parse_count; - buffer_state.last_selections_update_count = selections_update_count; - buffer_state.last_diagnostics_update_count = diagnostics_update_count; - buffer_state.last_file_update_count = file_update_count; - buffer_state.last_git_diff_update_count = git_diff_update_count; + buffer_state.last_non_text_state_update_count = non_text_state_update_count; excerpts_to_edit.extend( buffer_state .excerpts @@ -1870,23 +1834,15 @@ impl MultiBuffer { } edited |= buffer_edited; - reparsed |= buffer_reparsed; - diagnostics_updated |= buffer_diagnostics_updated; - git_diff_updated |= buffer_git_diff_updated; + non_text_state_updated |= buffer_non_text_state_updated; is_dirty |= buffer.is_dirty(); has_conflict |= buffer.has_conflict(); } if edited { snapshot.edit_count += 1; } - if reparsed { - snapshot.parse_count += 1; - } - if diagnostics_updated { - snapshot.diagnostics_update_count += 1; - } - if git_diff_updated { - snapshot.git_diff_update_count += 1; + if non_text_state_updated { + snapshot.non_text_state_update_count += 1; } snapshot.is_dirty = is_dirty; snapshot.has_conflict = has_conflict; @@ -3198,8 +3154,8 @@ impl MultiBufferSnapshot { self.edit_count } - pub fn parse_count(&self) -> usize { - self.parse_count + pub fn non_text_state_update_count(&self) -> usize { + self.non_text_state_update_count } /// Returns the smallest enclosing bracket ranges containing the given range or @@ -3412,14 +3368,6 @@ impl MultiBufferSnapshot { .collect() } - pub fn diagnostics_update_count(&self) -> usize { - self.diagnostics_update_count - } - - pub fn git_diff_update_count(&self) -> usize { - self.git_diff_update_count - } - pub fn trailing_excerpt_update_count(&self) -> usize { self.trailing_excerpt_update_count }