Improve the ergonomics of creating local buffers (#10347)

This PR renames `language::Buffer::new` to `language::Buffer::local` and
simplifies its interface. Instead of taking a replica id (which should
always be 0 for the local case) and a `BufferId`, which was awkward and
verbose to construct, it simply takes text and a `cx`.

It uses the `cx` to derive a `BufferId` from the `EntityId` associated
with the `cx`, which should always be positive based on the following
analysis...

We convert the entity id to a u64 using this method on `EntityId`, which
is defined by macros in the `slotmap` crate:

```rust
    pub fn as_ffi(self) -> u64 {
        (u64::from(self.version.get()) << 32) | u64::from(self.idx)
    }
```

If you look at the type of `version` in `KeyData`, it is non-zero:

```rust
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct KeyData {
    idx: u32,
    version: NonZeroU32,
}
```

This commit also adds `Context::reserve_model` and
`Context::insert_model` to determine a model's entity ID before it is
created, which we need in order to assign a `BufferId` in the background
when loading a buffer asynchronously.

Release Notes:

- N/A

---------

Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
This commit is contained in:
Nathan Sobo
2024-04-10 08:32:51 -06:00
committed by GitHub
co-authored by Piotr Osiewicz
parent 664efef76b
commit 7abb63cfda
31 changed files with 376 additions and 519 deletions
+22 -117
View File
@@ -38,8 +38,7 @@ fn test_edit_events(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let buffer = cx.new_model(|cx| {
let mut buffer =
language::Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "123456");
let mut buffer = language::Buffer::local("123456", cx);
buffer.set_group_interval(Duration::from_secs(1));
buffer
});
@@ -154,9 +153,7 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let mut now = Instant::now();
let buffer = cx.new_model(|cx| {
language::Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "123456")
});
let buffer = cx.new_model(|cx| language::Buffer::local("123456", cx));
let group_interval = buffer.update(cx, |buffer, _| buffer.transaction_group_interval());
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let editor = cx.add_window(|cx| build_editor(buffer.clone(), cx));
@@ -227,8 +224,7 @@ fn test_ime_composition(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let buffer = cx.new_model(|cx| {
let mut buffer =
language::Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcde");
let mut buffer = language::Buffer::local("abcde", cx);
// Ensure automatic grouping doesn't occur.
buffer.set_group_interval(Duration::ZERO);
buffer
@@ -2344,21 +2340,10 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) {
None,
));
let toml_buffer = cx.new_model(|cx| {
Buffer::new(
0,
BufferId::new(cx.entity_id().as_u64()).unwrap(),
"a = 1\nb = 2\n",
)
.with_language(toml_language, cx)
});
let toml_buffer =
cx.new_model(|cx| Buffer::local("a = 1\nb = 2\n", cx).with_language(toml_language, cx));
let rust_buffer = cx.new_model(|cx| {
Buffer::new(
0,
BufferId::new(cx.entity_id().as_u64()).unwrap(),
"const c: usize = 3;\n",
)
.with_language(rust_language, cx)
Buffer::local("const c: usize = 3;\n", cx).with_language(rust_language, cx)
});
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
@@ -4304,10 +4289,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) {
"#
.unindent();
let buffer = cx.new_model(|cx| {
Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
.with_language(language, cx)
});
let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let (view, cx) = cx.add_window_view(|cx| build_editor(buffer, cx));
@@ -4471,10 +4453,7 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) {
let text = "fn a() {}";
let buffer = cx.new_model(|cx| {
Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
.with_language(language, cx)
});
let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx));
editor
@@ -5129,10 +5108,7 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) {
"#
.unindent();
let buffer = cx.new_model(|cx| {
Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
.with_language(language, cx)
});
let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let (view, cx) = cx.add_window_view(|cx| build_editor(buffer, cx));
view.condition::<crate::EditorEvent>(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
@@ -5280,10 +5256,7 @@ async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) {
"#
.unindent();
let buffer = cx.new_model(|cx| {
Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
.with_language(language, cx)
});
let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx));
editor
@@ -5470,10 +5443,7 @@ async fn test_auto_replace_emoji_shortcode(cx: &mut gpui::TestAppContext) {
Some(tree_sitter_rust::language()),
));
let buffer = cx.new_model(|cx| {
Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "")
.with_language(language, cx)
});
let buffer = cx.new_model(|cx| Buffer::local("", cx).with_language(language, cx));
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx));
editor
@@ -6939,13 +6909,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.new_model(|cx| {
Buffer::new(
0,
BufferId::new(cx.entity_id().as_u64()).unwrap(),
sample_text(3, 4, 'a'),
)
});
let buffer = cx.new_model(|cx| Buffer::local(sample_text(3, 4, 'a'), cx));
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(
@@ -7029,13 +6993,7 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) {
primary: None,
}
});
let buffer = cx.new_model(|cx| {
Buffer::new(
0,
BufferId::new(cx.entity_id().as_u64()).unwrap(),
initial_text,
)
});
let buffer = cx.new_model(|cx| Buffer::local(initial_text, cx));
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(buffer, excerpt_ranges, cx);
@@ -7093,13 +7051,7 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) {
fn test_refresh_selections(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let buffer = cx.new_model(|cx| {
Buffer::new(
0,
BufferId::new(cx.entity_id().as_u64()).unwrap(),
sample_text(3, 4, 'a'),
)
});
let buffer = cx.new_model(|cx| Buffer::local(sample_text(3, 4, 'a'), cx));
let mut excerpt1_id = None;
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
@@ -7184,13 +7136,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.new_model(|cx| {
Buffer::new(
0,
BufferId::new(cx.entity_id().as_u64()).unwrap(),
sample_text(3, 4, 'a'),
)
});
let buffer = cx.new_model(|cx| Buffer::local(sample_text(3, 4, 'a'), cx));
let mut excerpt1_id = None;
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
@@ -7285,10 +7231,7 @@ async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
"{{} }\n", //
);
let buffer = cx.new_model(|cx| {
Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
.with_language(language, cx)
});
let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let (view, cx) = cx.add_window_view(|cx| build_editor(buffer, cx));
view.condition::<crate::EditorEvent>(cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
@@ -8989,31 +8932,13 @@ async fn test_multibuffer_reverts(cx: &mut gpui::TestAppContext) {
cx.executor().run_until_parked();
}
let buffer_1 = cx.new_model(|cx| {
Buffer::new(
0,
BufferId::new(cx.entity_id().as_u64()).unwrap(),
sample_text_1.clone(),
)
});
let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text_1.clone(), cx));
diff_every_buffer_row(&buffer_1, sample_text_1.clone(), cols, cx);
let buffer_2 = cx.new_model(|cx| {
Buffer::new(
1,
BufferId::new(cx.entity_id().as_u64() + 1).unwrap(),
sample_text_2.clone(),
)
});
let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text_2.clone(), cx));
diff_every_buffer_row(&buffer_2, sample_text_2.clone(), cols, cx);
let buffer_3 = cx.new_model(|cx| {
Buffer::new(
2,
BufferId::new(cx.entity_id().as_u64() + 2).unwrap(),
sample_text_3.clone(),
)
});
let buffer_3 = cx.new_model(|cx| Buffer::local(sample_text_3.clone(), cx));
diff_every_buffer_row(&buffer_3, sample_text_3.clone(), cols, cx);
let multibuffer = cx.new_model(|cx| {
@@ -9152,29 +9077,9 @@ async fn test_mutlibuffer_in_navigation_history(cx: &mut gpui::TestAppContext) {
"vvvv\nwwww\nxxxx\nyyyy\nzzzz\n{{{{\n||||\n}}}}\n~~~~\n\u{7f}\u{7f}\u{7f}\u{7f}"
);
let buffer_1 = cx.new_model(|cx| {
Buffer::new(
0,
BufferId::new(cx.entity_id().as_u64()).unwrap(),
sample_text_1.clone(),
)
});
let buffer_2 = cx.new_model(|cx| {
Buffer::new(
1,
BufferId::new(cx.entity_id().as_u64() + 1).unwrap(),
sample_text_2.clone(),
)
});
let buffer_3 = cx.new_model(|cx| {
Buffer::new(
2,
BufferId::new(cx.entity_id().as_u64() + 2).unwrap(),
sample_text_3.clone(),
)
});
let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text_1.clone(), cx));
let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text_2.clone(), cx));
let buffer_3 = cx.new_model(|cx| Buffer::local(sample_text_3.clone(), cx));
let multi_buffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);