language: Make Buffer::new take an explicit ID (#2900)

Piotr Osiewicz created

See Linear description for the full explanation of the issue. This PR is
mostly a mechanical change, except for the one case where we do pass in
an explicit `next_id` instead of `model_id` in project.rs.

Release Notes:
- Fixed a bug where some results were not reported in project search in
presence of unnamed buffers.

Change summary

crates/ai/src/assistant.rs             |  8 +-
crates/copilot/src/copilot.rs          |  4 
crates/editor/src/display_map.rs       |  9 +
crates/editor/src/editor.rs            |  6 
crates/editor/src/editor_tests.rs      | 41 +++++++-----
crates/editor/src/movement.rs          |  3 
crates/editor/src/multi_buffer.rs      | 47 ++++++++-----
crates/language/src/buffer.rs          |  8 -
crates/language/src/buffer_tests.rs    | 90 ++++++++++++++++-----------
crates/language_tools/src/lsp_log.rs   |  8 +
crates/project/src/project.rs          |  4 
crates/search/src/buffer_search.rs     |  6 
crates/zed/src/languages/c.rs          |  2 
crates/zed/src/languages/python.rs     |  2 
crates/zed/src/languages/rust.rs       |  2 
crates/zed/src/languages/typescript.rs |  5 
16 files changed, 141 insertions(+), 104 deletions(-)

Detailed changes

crates/ai/src/assistant.rs πŸ”—

@@ -855,14 +855,14 @@ impl Conversation {
     ) -> Self {
         let markdown = language_registry.language_for_name("Markdown");
         let buffer = cx.add_model(|cx| {
-            let mut buffer = Buffer::new(0, "", cx);
+            let mut buffer = Buffer::new(0, cx.model_id() as u64, "");
             buffer.set_language_registry(language_registry);
             cx.spawn_weak(|buffer, mut cx| async move {
                 let markdown = markdown.await?;
                 let buffer = buffer
                     .upgrade(&cx)
                     .ok_or_else(|| anyhow!("buffer was dropped"))?;
-                buffer.update(&mut cx, |buffer, cx| {
+                buffer.update(&mut cx, |buffer: &mut Buffer, cx| {
                     buffer.set_language(Some(markdown), cx)
                 });
                 anyhow::Ok(())
@@ -944,7 +944,7 @@ impl Conversation {
         let mut message_anchors = Vec::new();
         let mut next_message_id = MessageId(0);
         let buffer = cx.add_model(|cx| {
-            let mut buffer = Buffer::new(0, saved_conversation.text, cx);
+            let mut buffer = Buffer::new(0, cx.model_id() as u64, saved_conversation.text);
             for message in saved_conversation.messages {
                 message_anchors.push(MessageAnchor {
                     id: message.id,
@@ -958,7 +958,7 @@ impl Conversation {
                 let buffer = buffer
                     .upgrade(&cx)
                     .ok_or_else(|| anyhow!("buffer was dropped"))?;
-                buffer.update(&mut cx, |buffer, cx| {
+                buffer.update(&mut cx, |buffer: &mut Buffer, cx| {
                     buffer.set_language(Some(markdown), cx)
                 });
                 anyhow::Ok(())

crates/copilot/src/copilot.rs πŸ”—

@@ -980,7 +980,7 @@ mod tests {
         deterministic.forbid_parking();
         let (copilot, mut lsp) = Copilot::fake(cx);
 
-        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "Hello", cx));
+        let buffer_1 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "Hello"));
         let buffer_1_uri: lsp::Url = format!("buffer://{}", buffer_1.id()).parse().unwrap();
         copilot.update(cx, |copilot, cx| copilot.register_buffer(&buffer_1, cx));
         assert_eq!(
@@ -996,7 +996,7 @@ mod tests {
             }
         );
 
-        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "Goodbye", cx));
+        let buffer_2 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "Goodbye"));
         let buffer_2_uri: lsp::Url = format!("buffer://{}", buffer_2.id()).parse().unwrap();
         copilot.update(cx, |copilot, cx| copilot.register_buffer(&buffer_2, cx));
         assert_eq!(

crates/editor/src/display_map.rs πŸ”—

@@ -1362,7 +1362,8 @@ pub mod tests {
 
         cx.update(|cx| init_test(cx, |s| s.defaults.tab_size = Some(2.try_into().unwrap())));
 
-        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
+        let buffer = cx
+            .add_model(|cx| Buffer::new(0, cx.model_id() as u64, text).with_language(language, cx));
         buffer.condition(cx, |buf, _| !buf.is_parsing()).await;
         let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 
@@ -1451,7 +1452,8 @@ pub mod tests {
 
         cx.update(|cx| init_test(cx, |_| {}));
 
-        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
+        let buffer = cx
+            .add_model(|cx| Buffer::new(0, cx.model_id() as u64, text).with_language(language, cx));
         buffer.condition(cx, |buf, _| !buf.is_parsing()).await;
         let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 
@@ -1523,7 +1525,8 @@ pub mod tests {
 
         let (text, highlighted_ranges) = marked_text_ranges(r#"constˇ «a»: B = "c «d»""#, false);
 
-        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
+        let buffer = cx
+            .add_model(|cx| Buffer::new(0, cx.model_id() as u64, text).with_language(language, cx));
         buffer.condition(cx, |buf, _| !buf.is_parsing()).await;
 
         let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));

crates/editor/src/editor.rs πŸ”—

@@ -1271,7 +1271,7 @@ impl Editor {
         field_editor_style: Option<Arc<GetFieldEditorTheme>>,
         cx: &mut ViewContext<Self>,
     ) -> Self {
-        let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
+        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
         let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
         Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx)
     }
@@ -1280,7 +1280,7 @@ impl Editor {
         field_editor_style: Option<Arc<GetFieldEditorTheme>>,
         cx: &mut ViewContext<Self>,
     ) -> Self {
-        let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
+        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
         let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
         Self::new(EditorMode::Full, buffer, None, field_editor_style, cx)
     }
@@ -1290,7 +1290,7 @@ impl Editor {
         field_editor_style: Option<Arc<GetFieldEditorTheme>>,
         cx: &mut ViewContext<Self>,
     ) -> Self {
-        let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
+        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
         let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
         Self::new(
             EditorMode::AutoHeight { max_lines },

crates/editor/src/editor_tests.rs πŸ”—

@@ -42,7 +42,7 @@ fn test_edit_events(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let buffer = cx.add_model(|cx| {
-        let mut buffer = language::Buffer::new(0, "123456", cx);
+        let mut buffer = language::Buffer::new(0, cx.model_id() as u64, "123456");
         buffer.set_group_interval(Duration::from_secs(1));
         buffer
     });
@@ -174,7 +174,7 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut now = Instant::now();
-    let buffer = cx.add_model(|cx| language::Buffer::new(0, "123456", cx));
+    let buffer = cx.add_model(|cx| language::Buffer::new(0, cx.model_id() as u64, "123456"));
     let group_interval = buffer.read_with(cx, |buffer, _| buffer.transaction_group_interval());
     let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
     let editor = cx
@@ -247,7 +247,7 @@ fn test_ime_composition(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let buffer = cx.add_model(|cx| {
-        let mut buffer = language::Buffer::new(0, "abcde", cx);
+        let mut buffer = language::Buffer::new(0, cx.model_id() as u64, "abcde");
         // Ensure automatic grouping doesn't occur.
         buffer.set_group_interval(Duration::ZERO);
         buffer
@@ -2281,10 +2281,12 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) {
         None,
     ));
 
-    let toml_buffer =
-        cx.add_model(|cx| Buffer::new(0, "a = 1\nb = 2\n", cx).with_language(toml_language, cx));
+    let toml_buffer = cx.add_model(|cx| {
+        Buffer::new(0, cx.model_id() as u64, "a = 1\nb = 2\n").with_language(toml_language, cx)
+    });
     let rust_buffer = cx.add_model(|cx| {
-        Buffer::new(0, "const c: usize = 3;\n", cx).with_language(rust_language, cx)
+        Buffer::new(0, cx.model_id() as u64, "const c: usize = 3;\n")
+            .with_language(rust_language, cx)
     });
     let multibuffer = cx.add_model(|cx| {
         let mut multibuffer = MultiBuffer::new(0);
@@ -3754,7 +3756,8 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) {
     "#
     .unindent();
 
-    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
+    let buffer =
+        cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text).with_language(language, cx));
     let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
     let view = cx.add_window(|cx| build_editor(buffer, cx)).root(cx);
     view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
@@ -3917,7 +3920,8 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) {
 
     let text = "fn a() {}";
 
-    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
+    let buffer =
+        cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text).with_language(language, cx));
     let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
     let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx);
     editor
@@ -4480,7 +4484,8 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) {
     "#
     .unindent();
 
-    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
+    let buffer =
+        cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text).with_language(language, cx));
     let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
     let view = cx.add_window(|cx| build_editor(buffer, cx)).root(cx);
     view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
@@ -4628,7 +4633,8 @@ async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) {
     "#
     .unindent();
 
-    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
+    let buffer =
+        cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text).with_language(language, cx));
     let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
     let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx);
     editor
@@ -5834,7 +5840,7 @@ async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) {
 fn test_editing_disjoint_excerpts(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
-    let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
+    let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, sample_text(3, 4, 'a')));
     let multibuffer = cx.add_model(|cx| {
         let mut multibuffer = MultiBuffer::new(0);
         multibuffer.push_excerpts(
@@ -5918,7 +5924,7 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) {
             primary: None,
         }
     });
-    let buffer = cx.add_model(|cx| Buffer::new(0, initial_text, cx));
+    let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, initial_text));
     let multibuffer = cx.add_model(|cx| {
         let mut multibuffer = MultiBuffer::new(0);
         multibuffer.push_excerpts(buffer, excerpt_ranges, cx);
@@ -5976,7 +5982,7 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) {
 fn test_refresh_selections(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
-    let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
+    let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, sample_text(3, 4, 'a')));
     let mut excerpt1_id = None;
     let multibuffer = cx.add_model(|cx| {
         let mut multibuffer = MultiBuffer::new(0);
@@ -6063,7 +6069,7 @@ fn test_refresh_selections(cx: &mut TestAppContext) {
 fn test_refresh_selections_while_selecting_with_mouse(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
-    let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
+    let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, sample_text(3, 4, 'a')));
     let mut excerpt1_id = None;
     let multibuffer = cx.add_model(|cx| {
         let mut multibuffer = MultiBuffer::new(0);
@@ -6160,7 +6166,8 @@ async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
         "{{} }\n",     //
     );
 
-    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
+    let buffer =
+        cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text).with_language(language, cx));
     let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
     let view = cx.add_window(|cx| build_editor(buffer, cx)).root(cx);
     view.condition(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
@@ -7160,8 +7167,8 @@ async fn test_copilot_multibuffer(
     let (copilot, copilot_lsp) = Copilot::fake(cx);
     cx.update(|cx| cx.set_global(copilot));
 
-    let buffer_1 = cx.add_model(|cx| Buffer::new(0, "a = 1\nb = 2\n", cx));
-    let buffer_2 = cx.add_model(|cx| Buffer::new(0, "c = 3\nd = 4\n", cx));
+    let buffer_1 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "a = 1\nb = 2\n"));
+    let buffer_2 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "c = 3\nd = 4\n"));
     let multibuffer = cx.add_model(|cx| {
         let mut multibuffer = MultiBuffer::new(0);
         multibuffer.push_excerpts(

crates/editor/src/movement.rs πŸ”—

@@ -756,7 +756,8 @@ mod tests {
             .select_font(family_id, &Default::default())
             .unwrap();
 
-        let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndefg\nhijkl\nmn", cx));
+        let buffer =
+            cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abc\ndefg\nhijkl\nmn"));
         let multibuffer = cx.add_model(|cx| {
             let mut multibuffer = MultiBuffer::new(0);
             multibuffer.push_excerpts(

crates/editor/src/multi_buffer.rs πŸ”—

@@ -1570,7 +1570,7 @@ impl MultiBuffer {
 #[cfg(any(test, feature = "test-support"))]
 impl MultiBuffer {
     pub fn build_simple(text: &str, cx: &mut gpui::AppContext) -> ModelHandle<Self> {
-        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
+        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text));
         cx.add_model(|cx| Self::singleton(buffer, cx))
     }
 
@@ -1580,7 +1580,7 @@ impl MultiBuffer {
     ) -> ModelHandle<Self> {
         let multi = cx.add_model(|_| Self::new(0));
         for (text, ranges) in excerpts {
-            let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
+            let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text));
             let excerpt_ranges = ranges.into_iter().map(|range| ExcerptRange {
                 context: range,
                 primary: None,
@@ -1672,7 +1672,7 @@ impl MultiBuffer {
             if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) {
                 let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() {
                     let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
-                    buffers.push(cx.add_model(|cx| Buffer::new(0, text, cx)));
+                    buffers.push(cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text)));
                     let buffer = buffers.last().unwrap().read(cx);
                     log::info!(
                         "Creating new buffer {} with text: {:?}",
@@ -4022,7 +4022,8 @@ mod tests {
 
     #[gpui::test]
     fn test_singleton(cx: &mut AppContext) {
-        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
+        let buffer =
+            cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, sample_text(6, 6, 'a')));
         let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
 
         let snapshot = multibuffer.read(cx).snapshot(cx);
@@ -4049,7 +4050,7 @@ mod tests {
 
     #[gpui::test]
     fn test_remote(cx: &mut AppContext) {
-        let host_buffer = cx.add_model(|cx| Buffer::new(0, "a", cx));
+        let host_buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "a"));
         let guest_buffer = cx.add_model(|cx| {
             let state = host_buffer.read(cx).to_proto();
             let ops = cx
@@ -4080,8 +4081,10 @@ mod tests {
 
     #[gpui::test]
     fn test_excerpt_boundaries_and_clipping(cx: &mut AppContext) {
-        let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
-        let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
+        let buffer_1 =
+            cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, sample_text(6, 6, 'a')));
+        let buffer_2 =
+            cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, sample_text(6, 6, 'g')));
         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
 
         let events = Rc::new(RefCell::new(Vec::<Event>::new()));
@@ -4314,8 +4317,10 @@ mod tests {
 
     #[gpui::test]
     fn test_excerpt_events(cx: &mut AppContext) {
-        let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(10, 3, 'a'), cx));
-        let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(10, 3, 'm'), cx));
+        let buffer_1 =
+            cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, sample_text(10, 3, 'a')));
+        let buffer_2 =
+            cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, sample_text(10, 3, 'm')));
 
         let leader_multibuffer = cx.add_model(|_| MultiBuffer::new(0));
         let follower_multibuffer = cx.add_model(|_| MultiBuffer::new(0));
@@ -4420,7 +4425,8 @@ mod tests {
 
     #[gpui::test]
     fn test_push_excerpts_with_context_lines(cx: &mut AppContext) {
-        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(20, 3, 'a'), cx));
+        let buffer =
+            cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, sample_text(20, 3, 'a')));
         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
         let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
             multibuffer.push_excerpts_with_context_lines(
@@ -4456,7 +4462,8 @@ mod tests {
 
     #[gpui::test]
     async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) {
-        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(20, 3, 'a'), cx));
+        let buffer =
+            cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, sample_text(20, 3, 'a')));
         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
         let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
             let snapshot = buffer.read(cx);
@@ -4502,7 +4509,7 @@ mod tests {
 
     #[gpui::test]
     fn test_singleton_multibuffer_anchors(cx: &mut AppContext) {
-        let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
+        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abcd"));
         let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
         let old_snapshot = multibuffer.read(cx).snapshot(cx);
         buffer.update(cx, |buffer, cx| {
@@ -4522,8 +4529,8 @@ mod tests {
 
     #[gpui::test]
     fn test_multibuffer_anchors(cx: &mut AppContext) {
-        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
-        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
+        let buffer_1 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abcd"));
+        let buffer_2 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "efghi"));
         let multibuffer = cx.add_model(|cx| {
             let mut multibuffer = MultiBuffer::new(0);
             multibuffer.push_excerpts(
@@ -4580,8 +4587,8 @@ mod tests {
 
     #[gpui::test]
     fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut AppContext) {
-        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
-        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "ABCDEFGHIJKLMNOP", cx));
+        let buffer_1 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abcd"));
+        let buffer_2 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "ABCDEFGHIJKLMNOP"));
         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
 
         // Create an insertion id in buffer 1 that doesn't exist in buffer 2.
@@ -4976,7 +4983,9 @@ mod tests {
                         let base_text = util::RandomCharIter::new(&mut rng)
                             .take(10)
                             .collect::<String>();
-                        buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
+                        buffers.push(
+                            cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, base_text)),
+                        );
                         buffers.last().unwrap()
                     } else {
                         buffers.choose(&mut rng).unwrap()
@@ -5317,8 +5326,8 @@ mod tests {
     fn test_history(cx: &mut AppContext) {
         cx.set_global(SettingsStore::test(cx));
 
-        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
-        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
+        let buffer_1 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "1234"));
+        let buffer_2 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "5678"));
         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
         let group_interval = multibuffer.read(cx).history.group_interval;
         multibuffer.update(cx, |multibuffer, cx| {

crates/language/src/buffer.rs πŸ”—

@@ -347,13 +347,9 @@ impl CharKind {
 }
 
 impl Buffer {
-    pub fn new<T: Into<String>>(
-        replica_id: ReplicaId,
-        base_text: T,
-        cx: &mut ModelContext<Self>,
-    ) -> Self {
+    pub fn new<T: Into<String>>(replica_id: ReplicaId, id: u64, base_text: T) -> Self {
         Self::build(
-            TextBuffer::new(replica_id, cx.model_id() as u64, base_text.into()),
+            TextBuffer::new(replica_id, id, base_text.into()),
             None,
             None,
         )

crates/language/src/buffer_tests.rs πŸ”—

@@ -43,8 +43,8 @@ fn test_line_endings(cx: &mut gpui::AppContext) {
     init_settings(cx, |_| {});
 
     cx.add_model(|cx| {
-        let mut buffer =
-            Buffer::new(0, "one\r\ntwo\rthree", cx).with_language(Arc::new(rust_lang()), cx);
+        let mut buffer = Buffer::new(0, cx.model_id() as u64, "one\r\ntwo\rthree")
+            .with_language(Arc::new(rust_lang()), cx);
         assert_eq!(buffer.text(), "one\ntwo\nthree");
         assert_eq!(buffer.line_ending(), LineEnding::Windows);
 
@@ -138,8 +138,8 @@ fn test_edit_events(cx: &mut gpui::AppContext) {
     let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
     let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
 
-    let buffer1 = cx.add_model(|cx| Buffer::new(0, "abcdef", cx));
-    let buffer2 = cx.add_model(|cx| Buffer::new(1, "abcdef", cx));
+    let buffer1 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abcdef"));
+    let buffer2 = cx.add_model(|cx| Buffer::new(1, cx.model_id() as u64, "abcdef"));
     let buffer1_ops = Rc::new(RefCell::new(Vec::new()));
     buffer1.update(cx, {
         let buffer1_ops = buffer1_ops.clone();
@@ -222,7 +222,7 @@ fn test_edit_events(cx: &mut gpui::AppContext) {
 #[gpui::test]
 async fn test_apply_diff(cx: &mut gpui::TestAppContext) {
     let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
-    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
+    let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text));
     let anchor = buffer.read_with(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
 
     let text = "a\nccc\ndddd\nffffff\n";
@@ -254,7 +254,7 @@ async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
     ]
     .join("\n");
 
-    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
+    let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text));
 
     // Spawn a task to format the buffer's whitespace.
     // Pause so that the foratting task starts running.
@@ -318,8 +318,9 @@ async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
 #[gpui::test]
 async fn test_reparse(cx: &mut gpui::TestAppContext) {
     let text = "fn a() {}";
-    let buffer =
-        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
+    let buffer = cx.add_model(|cx| {
+        Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx)
+    });
 
     // Wait for the initial text to parse
     buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
@@ -443,7 +444,8 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
 #[gpui::test]
 async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
     let buffer = cx.add_model(|cx| {
-        let mut buffer = Buffer::new(0, "{}", cx).with_language(Arc::new(rust_lang()), cx);
+        let mut buffer =
+            Buffer::new(0, cx.model_id() as u64, "{}").with_language(Arc::new(rust_lang()), cx);
         buffer.set_sync_parse_timeout(Duration::ZERO);
         buffer
     });
@@ -491,8 +493,9 @@ async fn test_outline(cx: &mut gpui::TestAppContext) {
     "#
     .unindent();
 
-    let buffer =
-        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
+    let buffer = cx.add_model(|cx| {
+        Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx)
+    });
     let outline = buffer
         .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
         .unwrap();
@@ -576,8 +579,9 @@ async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) {
     "#
     .unindent();
 
-    let buffer =
-        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
+    let buffer = cx.add_model(|cx| {
+        Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx)
+    });
     let outline = buffer
         .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
         .unwrap();
@@ -613,7 +617,9 @@ async fn test_outline_with_extra_context(cx: &mut gpui::TestAppContext) {
     "#
     .unindent();
 
-    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(language), cx));
+    let buffer = cx.add_model(|cx| {
+        Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(language), cx)
+    });
     let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
 
     // extra context nodes are included in the outline.
@@ -655,8 +661,9 @@ async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
     "#
     .unindent();
 
-    let buffer =
-        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
+    let buffer = cx.add_model(|cx| {
+        Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx)
+    });
     let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
 
     // point is at the start of an item
@@ -877,7 +884,8 @@ fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &
 fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
     cx.add_model(|cx| {
         let text = "fn a() { b(|c| {}) }";
-        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
+        let buffer =
+            Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
         let snapshot = buffer.snapshot();
 
         assert_eq!(
@@ -917,7 +925,8 @@ fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
 
     cx.add_model(|cx| {
         let text = "fn a() {}";
-        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
+        let mut buffer =
+            Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
 
         buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
         assert_eq!(buffer.text(), "fn a() {\n    \n}");
@@ -959,7 +968,8 @@ fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
 
     cx.add_model(|cx| {
         let text = "fn a() {}";
-        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
+        let mut buffer =
+            Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
 
         buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
         assert_eq!(buffer.text(), "fn a() {\n\t\n}");
@@ -1000,6 +1010,7 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppC
     cx.add_model(|cx| {
         let mut buffer = Buffer::new(
             0,
+            cx.model_id() as u64,
             "
             fn a() {
             c;
@@ -1007,7 +1018,6 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppC
             }
             "
             .unindent(),
-            cx,
         )
         .with_language(Arc::new(rust_lang()), cx);
 
@@ -1073,6 +1083,7 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppC
     cx.add_model(|cx| {
         let mut buffer = Buffer::new(
             0,
+            cx.model_id() as u64,
             "
             fn a() {
                 b();
@@ -1080,7 +1091,6 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppC
             "
             .replace("|", "") // marker to preserve trailing whitespace
             .unindent(),
-            cx,
         )
         .with_language(Arc::new(rust_lang()), cx);
 
@@ -1136,13 +1146,13 @@ fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut Ap
     cx.add_model(|cx| {
         let mut buffer = Buffer::new(
             0,
+            cx.model_id() as u64,
             "
             fn a() {
                 i
             }
             "
             .unindent(),
-            cx,
         )
         .with_language(Arc::new(rust_lang()), cx);
 
@@ -1198,11 +1208,11 @@ fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
     cx.add_model(|cx| {
         let mut buffer = Buffer::new(
             0,
+            cx.model_id() as u64,
             "
             fn a() {}
             "
             .unindent(),
-            cx,
         )
         .with_language(Arc::new(rust_lang()), cx);
 
@@ -1254,7 +1264,8 @@ fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
 
     cx.add_model(|cx| {
         let text = "a\nb";
-        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
+        let mut buffer =
+            Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
         buffer.edit(
             [(0..1, "\n"), (2..3, "\n")],
             Some(AutoindentMode::EachLine),
@@ -1280,7 +1291,8 @@ fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
         "
         .unindent();
 
-        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
+        let mut buffer =
+            Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
         buffer.edit(
             [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
             Some(AutoindentMode::EachLine),
@@ -1317,7 +1329,8 @@ fn test_autoindent_block_mode(cx: &mut AppContext) {
             }
         "#
         .unindent();
-        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
+        let mut buffer =
+            Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
 
         // When this text was copied, both of the quotation marks were at the same
         // indent level, but the indentation of the first line was not included in
@@ -1402,7 +1415,8 @@ fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContex
             }
         "#
         .unindent();
-        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
+        let mut buffer =
+            Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
 
         // The original indent columns are not known, so this text is
         // auto-indented in a block as if the first line was copied in
@@ -1481,7 +1495,7 @@ fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
         "
         .unindent();
 
-        let mut buffer = Buffer::new(0, text, cx).with_language(
+        let mut buffer = Buffer::new(0, cx.model_id() as u64, text).with_language(
             Arc::new(Language::new(
                 LanguageConfig {
                     name: "Markdown".into(),
@@ -1557,7 +1571,7 @@ fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
             false,
         );
 
-        let mut buffer = Buffer::new(0, text, cx);
+        let mut buffer = Buffer::new(0, cx.model_id() as u64, text);
         buffer.set_language_registry(language_registry);
         buffer.set_language(Some(html_language), cx);
         buffer.edit(
@@ -1593,7 +1607,8 @@ fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
     });
 
     cx.add_model(|cx| {
-        let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(ruby_lang()), cx);
+        let mut buffer =
+            Buffer::new(0, cx.model_id() as u64, "").with_language(Arc::new(ruby_lang()), cx);
 
         let text = r#"
             class C
@@ -1683,7 +1698,8 @@ fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
 
         let text = r#"a["b"] = <C d="e"></C>;"#;
 
-        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(language), cx);
+        let buffer =
+            Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(language), cx);
         let snapshot = buffer.snapshot();
 
         let config = snapshot.language_scope_at(0).unwrap();
@@ -1762,7 +1778,8 @@ fn test_language_scope_at_with_rust(cx: &mut AppContext) {
         "#
         .unindent();
 
-        let buffer = Buffer::new(0, text.clone(), cx).with_language(Arc::new(language), cx);
+        let buffer = Buffer::new(0, cx.model_id() as u64, text.clone())
+            .with_language(Arc::new(language), cx);
         let snapshot = buffer.snapshot();
 
         // By default, all brackets are enabled
@@ -1806,7 +1823,7 @@ fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
         language_registry.add(Arc::new(html_lang()));
         language_registry.add(Arc::new(erb_lang()));
 
-        let mut buffer = Buffer::new(0, text, cx);
+        let mut buffer = Buffer::new(0, cx.model_id() as u64, text);
         buffer.set_language_registry(language_registry.clone());
         buffer.set_language(
             language_registry
@@ -1838,7 +1855,7 @@ fn test_serialization(cx: &mut gpui::AppContext) {
     let mut now = Instant::now();
 
     let buffer1 = cx.add_model(|cx| {
-        let mut buffer = Buffer::new(0, "abc", cx);
+        let mut buffer = Buffer::new(0, cx.model_id() as u64, "abc");
         buffer.edit([(3..3, "D")], None, cx);
 
         now += Duration::from_secs(1);
@@ -1893,7 +1910,7 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
     let mut replica_ids = Vec::new();
     let mut buffers = Vec::new();
     let network = Rc::new(RefCell::new(Network::new(rng.clone())));
-    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
+    let base_buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, base_text.as_str()));
 
     for i in 0..rng.gen_range(min_peers..=max_peers) {
         let buffer = cx.add_model(|cx| {
@@ -2394,7 +2411,8 @@ fn assert_bracket_pairs(
 ) {
     let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
     let buffer = cx.add_model(|cx| {
-        Buffer::new(0, expected_text.clone(), cx).with_language(Arc::new(language), cx)
+        Buffer::new(0, cx.model_id() as u64, expected_text.clone())
+            .with_language(Arc::new(language), cx)
     });
     let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
 

crates/language_tools/src/lsp_log.rs πŸ”—

@@ -176,7 +176,9 @@ impl LogStore {
                     cx.notify();
                     LanguageServerState {
                         rpc_state: None,
-                        log_buffer: cx.add_model(|cx| Buffer::new(0, "", cx)).clone(),
+                        log_buffer: cx
+                            .add_model(|cx| Buffer::new(0, cx.model_id() as u64, ""))
+                            .clone(),
                     }
                 })
                 .log_buffer
@@ -241,7 +243,7 @@ impl LogStore {
         let rpc_state = server_state.rpc_state.get_or_insert_with(|| {
             let io_tx = self.io_tx.clone();
             let language = project.read(cx).languages().language_for_name("JSON");
-            let buffer = cx.add_model(|cx| Buffer::new(0, "", cx));
+            let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, ""));
             cx.spawn_weak({
                 let buffer = buffer.clone();
                 |_, mut cx| async move {
@@ -327,7 +329,7 @@ impl LspLogView {
             .projects
             .get(&project.downgrade())
             .and_then(|project| project.servers.keys().copied().next());
-        let buffer = cx.add_model(|cx| Buffer::new(0, "", cx));
+        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, ""));
         let mut this = Self {
             editor: Self::editor_for_buffer(project.clone(), buffer, cx),
             project,

crates/project/src/project.rs πŸ”—

@@ -1568,9 +1568,9 @@ impl Project {
         if self.is_remote() {
             return Err(anyhow!("creating buffers as a guest is not supported yet"));
         }
-
+        let id = post_inc(&mut self.next_buffer_id);
         let buffer = cx.add_model(|cx| {
-            Buffer::new(self.replica_id(), text, cx)
+            Buffer::new(self.replica_id(), id, text)
                 .with_language(language.unwrap_or_else(|| language::PLAIN_TEXT.clone()), cx)
         });
         self.register_buffer(&buffer, cx)?;

crates/search/src/buffer_search.rs πŸ”—

@@ -837,6 +837,7 @@ mod tests {
         let buffer = cx.add_model(|cx| {
             Buffer::new(
                 0,
+                cx.model_id() as u64,
                 r#"
                 A regular expression (shortened as regex or regexp;[1] also referred to as
                 rational expression[2][3]) is a sequence of characters that specifies a search
@@ -844,7 +845,6 @@ mod tests {
                 for "find" or "find and replace" operations on strings, or for input validation.
                 "#
                 .unindent(),
-                cx,
             )
         });
         let window = cx.add_window(|_| EmptyView);
@@ -1225,7 +1225,7 @@ mod tests {
             expected_query_matches_count > 1,
             "Should pick a query with multiple results"
         );
-        let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx));
+        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, buffer_text));
         let window = cx.add_window(|_| EmptyView);
         let editor = window.add_view(cx, |cx| Editor::for_buffer(buffer.clone(), None, cx));
 
@@ -1412,7 +1412,7 @@ mod tests {
         for "find" or "find and replace" operations on strings, or for input validation.
         "#
         .unindent();
-        let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx));
+        let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, buffer_text));
         let window = cx.add_window(|_| EmptyView);
 
         let editor = window.add_view(cx, |cx| Editor::for_buffer(buffer.clone(), None, cx));

crates/zed/src/languages/c.rs πŸ”—

@@ -289,7 +289,7 @@ mod tests {
         let language = crate::languages::language("c", tree_sitter_c::language(), None).await;
 
         cx.add_model(|cx| {
-            let mut buffer = Buffer::new(0, "", cx).with_language(language, cx);
+            let mut buffer = Buffer::new(0, cx.model_id() as u64, "").with_language(language, cx);
 
             // empty function
             buffer.edit([(0..0, "int main() {}")], None, cx);

crates/zed/src/languages/python.rs πŸ”—

@@ -210,7 +210,7 @@ mod tests {
         });
 
         cx.add_model(|cx| {
-            let mut buffer = Buffer::new(0, "", cx).with_language(language, cx);
+            let mut buffer = Buffer::new(0, cx.model_id() as u64, "").with_language(language, cx);
             let append = |buffer: &mut Buffer, text: &str, cx: &mut ModelContext<Buffer>| {
                 let ix = buffer.len();
                 buffer.edit([(ix..ix, text)], Some(AutoindentMode::EachLine), cx);

crates/zed/src/languages/rust.rs πŸ”—

@@ -474,7 +474,7 @@ mod tests {
         let language = crate::languages::language("rust", tree_sitter_rust::language(), None).await;
 
         cx.add_model(|cx| {
-            let mut buffer = Buffer::new(0, "", cx).with_language(language, cx);
+            let mut buffer = Buffer::new(0, cx.model_id() as u64, "").with_language(language, cx);
 
             // indent between braces
             buffer.set_text("fn a() {}", cx);

crates/zed/src/languages/typescript.rs πŸ”—

@@ -356,8 +356,9 @@ mod tests {
         "#
         .unindent();
 
-        let buffer =
-            cx.add_model(|cx| language::Buffer::new(0, text, cx).with_language(language, cx));
+        let buffer = cx.add_model(|cx| {
+            language::Buffer::new(0, cx.model_id() as u64, text).with_language(language, cx)
+        });
         let outline = buffer.read_with(cx, |buffer, _| buffer.snapshot().outline(None).unwrap());
         assert_eq!(
             outline