Detailed changes
@@ -35,7 +35,7 @@ use gpui::{
StatefulInteractiveElement, Styled, Subscription, Task, TextStyle, UniformListScrollHandle,
View, ViewContext, VisualContext, WeakModel, WeakView, WhiteSpace, WindowContext,
};
-use language::{language_settings::SoftWrap, Buffer, LanguageRegistry, ToOffset as _};
+use language::{language_settings::SoftWrap, Buffer, BufferId, LanguageRegistry, ToOffset as _};
use project::Project;
use search::{buffer_search::DivRegistrar, BufferSearchBar};
use semantic_index::{SemanticIndex, SemanticIndexStatus};
@@ -1414,7 +1414,7 @@ impl Conversation {
) -> Self {
let markdown = language_registry.language_for_name("Markdown");
let buffer = cx.new_model(|cx| {
- let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "");
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "");
buffer.set_language_registry(language_registry);
cx.spawn(|buffer, mut cx| async move {
let markdown = markdown.await?;
@@ -1515,7 +1515,11 @@ impl Conversation {
let mut message_anchors = Vec::new();
let mut next_message_id = MessageId(0);
let buffer = cx.new_model(|cx| {
- let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), saved_conversation.text);
+ let mut buffer = Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ saved_conversation.text,
+ );
for message in saved_conversation.messages {
message_anchors.push(MessageAnchor {
id: message.id,
@@ -365,7 +365,9 @@ mod tests {
use futures::stream::{self};
use gpui::{Context, TestAppContext};
use indoc::indoc;
- use language::{language_settings, tree_sitter_rust, Buffer, Language, LanguageConfig, Point};
+ use language::{
+ language_settings, tree_sitter_rust, Buffer, BufferId, Language, LanguageConfig, Point,
+ };
use rand::prelude::*;
use serde::Serialize;
use settings::SettingsStore;
@@ -394,8 +396,9 @@ mod tests {
}
}
"};
- let buffer =
- cx.new_model(|cx| Buffer::new(0, 0, text).with_language(Arc::new(rust_lang()), cx));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(1).unwrap(), text).with_language(Arc::new(rust_lang()), cx)
+ });
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let range = buffer.read_with(cx, |buffer, cx| {
let snapshot = buffer.snapshot(cx);
@@ -460,8 +463,9 @@ mod tests {
le
}
"};
- let buffer =
- cx.new_model(|cx| Buffer::new(0, 0, text).with_language(Arc::new(rust_lang()), cx));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(1).unwrap(), text).with_language(Arc::new(rust_lang()), cx)
+ });
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let position = buffer.read_with(cx, |buffer, cx| {
let snapshot = buffer.snapshot(cx);
@@ -525,8 +529,9 @@ mod tests {
" \n",
"}\n" //
);
- let buffer =
- cx.new_model(|cx| Buffer::new(0, 0, text).with_language(Arc::new(rust_lang()), cx));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(1).unwrap(), text).with_language(Arc::new(rust_lang()), cx)
+ });
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
let position = buffer.read_with(cx, |buffer, cx| {
let snapshot = buffer.snapshot(cx);
@@ -178,7 +178,9 @@ pub(crate) mod tests {
use gpui::{AppContext, Context};
use indoc::indoc;
- use language::{language_settings, tree_sitter_rust, Buffer, Language, LanguageConfig, Point};
+ use language::{
+ language_settings, tree_sitter_rust, Buffer, BufferId, Language, LanguageConfig, Point,
+ };
use settings::SettingsStore;
pub(crate) fn rust_lang() -> Language {
@@ -253,8 +255,9 @@ pub(crate) mod tests {
}
}
"};
- let buffer =
- cx.new_model(|cx| Buffer::new(0, 0, text).with_language(Arc::new(rust_lang()), cx));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(1).unwrap(), text).with_language(Arc::new(rust_lang()), cx)
+ });
let snapshot = buffer.read(cx).snapshot();
assert_eq!(
@@ -9,6 +9,7 @@ use rpc::{
TypedEnvelope,
};
use std::{sync::Arc, time::Duration};
+use text::BufferId;
use util::ResultExt;
pub const ACKNOWLEDGE_DEBOUNCE_INTERVAL: Duration = Duration::from_millis(250);
@@ -53,7 +54,7 @@ impl ChannelBuffer {
channel_id: channel.id,
})
.await?;
-
+ let buffer_id = BufferId::new(response.buffer_id)?;
let base_text = response.base_text;
let operations = response
.operations
@@ -63,12 +64,7 @@ impl ChannelBuffer {
let buffer = cx.new_model(|cx| {
let capability = channel_store.read(cx).channel_capability(channel.id);
- language::Buffer::remote(
- response.buffer_id,
- response.replica_id as u16,
- capability,
- base_text,
- )
+ language::Buffer::remote(buffer_id, response.replica_id as u16, capability, base_text)
})?;
buffer.update(&mut cx, |buffer, cx| buffer.apply_ops(operations, cx))??;
@@ -107,7 +103,7 @@ impl ChannelBuffer {
}
}
- pub fn remote_id(&self, cx: &AppContext) -> u64 {
+ pub fn remote_id(&self, cx: &AppContext) -> BufferId {
self.buffer.read(cx).remote_id()
}
@@ -210,7 +206,7 @@ impl ChannelBuffer {
pub fn acknowledge_buffer_version(&mut self, cx: &mut ModelContext<'_, ChannelBuffer>) {
let buffer = self.buffer.read(cx);
let version = buffer.version();
- let buffer_id = buffer.remote_id();
+ let buffer_id = buffer.remote_id().into();
let client = self.client.clone();
let epoch = self.epoch();
@@ -693,7 +693,7 @@ impl Database {
return Ok(());
}
- let mut text_buffer = text::Buffer::new(0, 0, base_text);
+ let mut text_buffer = text::Buffer::new(0, text::BufferId::new(1).unwrap(), base_text);
text_buffer
.apply_ops(operations.into_iter().filter_map(operation_from_wire))
.unwrap();
@@ -67,7 +67,7 @@ async fn test_channel_buffers(db: &Arc<Database>) {
.await
.unwrap();
- let mut buffer_a = Buffer::new(0, 0, "".to_string());
+ let mut buffer_a = Buffer::new(0, text::BufferId::new(0).unwrap(), "".to_string());
let mut operations = Vec::new();
operations.push(buffer_a.edit([(0..0, "hello world")]));
operations.push(buffer_a.edit([(5..5, ", cruel")]));
@@ -90,7 +90,11 @@ async fn test_channel_buffers(db: &Arc<Database>) {
.await
.unwrap();
- let mut buffer_b = Buffer::new(0, 0, buffer_response_b.base_text);
+ let mut buffer_b = Buffer::new(
+ 0,
+ text::BufferId::new(0).unwrap(),
+ buffer_response_b.base_text,
+ );
buffer_b
.apply_ops(buffer_response_b.operations.into_iter().map(|operation| {
let operation = proto::deserialize_operation(operation).unwrap();
@@ -223,7 +227,11 @@ async fn test_channel_buffers_last_operations(db: &Database) {
.unwrap(),
);
- text_buffers.push(Buffer::new(0, 0, "".to_string()));
+ text_buffers.push(Buffer::new(
+ 0,
+ text::BufferId::new(1).unwrap(),
+ "".to_string(),
+ ));
}
let operations = db
@@ -270,7 +278,7 @@ async fn test_channel_buffers_last_operations(db: &Database) {
db.join_channel_buffer(buffers[1].channel_id, user_id, connection_id)
.await
.unwrap();
- text_buffers[1] = Buffer::new(1, 0, "def".to_string());
+ text_buffers[1] = Buffer::new(1, text::BufferId::new(1).unwrap(), "def".to_string());
update_buffer(
buffers[1].channel_id,
user_id,
@@ -1023,12 +1023,15 @@ async fn get_copilot_lsp(http: Arc<dyn HttpClient>) -> anyhow::Result<PathBuf> {
mod tests {
use super::*;
use gpui::TestAppContext;
+ use language::BufferId;
#[gpui::test(iterations = 10)]
async fn test_buffer_management(cx: &mut TestAppContext) {
let (copilot, mut lsp) = Copilot::fake(cx);
- let buffer_1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "Hello"));
+ let buffer_1 = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "Hello")
+ });
let buffer_1_uri: lsp::Url = format!("buffer://{}", buffer_1.entity_id().as_u64())
.parse()
.unwrap();
@@ -1046,7 +1049,13 @@ mod tests {
}
);
- let buffer_2 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "Goodbye"));
+ let buffer_2 = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ "Goodbye",
+ )
+ });
let buffer_2_uri: lsp::Url = format!("buffer://{}", buffer_2.entity_id().as_u64())
.parse()
.unwrap();
@@ -1235,7 +1244,7 @@ mod tests {
fn buffer_reloaded(
&self,
- _: u64,
+ _: BufferId,
_: &clock::Global,
_: language::RopeFingerprint,
_: language::LineEnding,
@@ -1007,6 +1007,7 @@ pub mod tests {
use settings::SettingsStore;
use smol::stream::StreamExt;
use std::{env, sync::Arc};
+ use text::BufferId;
use theme::{LoadThemes, SyntaxTheme};
use util::test::{marked_text_ranges, sample_text};
use Bias::*;
@@ -1467,7 +1468,8 @@ pub mod tests {
cx.update(|cx| init_test(cx, |s| s.defaults.tab_size = Some(2.try_into().unwrap())));
let buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx)
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(language, cx)
});
cx.condition(&buffer, |buf, _| !buf.is_parsing()).await;
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
@@ -1553,7 +1555,8 @@ pub mod tests {
cx.update(|cx| init_test(cx, |_| {}));
let buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx)
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(language, cx)
});
cx.condition(&buffer, |buf, _| !buf.is_parsing()).await;
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
@@ -1620,7 +1623,8 @@ pub mod tests {
let (text, highlighted_ranges) = marked_text_ranges(r#"constΛ Β«aΒ»: B = "c Β«dΒ»""#, false);
let buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx)
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(language, cx)
});
cx.condition(&buffer, |buf, _| !buf.is_parsing()).await;
@@ -109,7 +109,7 @@ use std::{
};
pub use sum_tree::Bias;
use sum_tree::TreeMap;
-use text::{OffsetUtf16, Rope};
+use text::{BufferId, OffsetUtf16, Rope};
use theme::{
observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme,
ThemeColors, ThemeSettings,
@@ -1289,19 +1289,37 @@ impl InlayHintRefreshReason {
impl Editor {
pub fn single_line(cx: &mut ViewContext<Self>) -> Self {
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), String::new()));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ String::new(),
+ )
+ });
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
Self::new(EditorMode::SingleLine, buffer, None, cx)
}
pub fn multi_line(cx: &mut ViewContext<Self>) -> Self {
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), String::new()));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ String::new(),
+ )
+ });
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
Self::new(EditorMode::Full, buffer, None, cx)
}
pub fn auto_height(max_lines: usize, cx: &mut ViewContext<Self>) -> Self {
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), String::new()));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ String::new(),
+ )
+ });
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
Self::new(EditorMode::AutoHeight { max_lines }, buffer, None, cx)
}
@@ -39,7 +39,8 @@ fn test_edit_events(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let buffer = cx.new_model(|cx| {
- let mut buffer = language::Buffer::new(0, cx.entity_id().as_u64(), "123456");
+ let mut buffer =
+ language::Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "123456");
buffer.set_group_interval(Duration::from_secs(1));
buffer
});
@@ -154,7 +155,9 @@ 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, cx.entity_id().as_u64(), "123456"));
+ let buffer = cx.new_model(|cx| {
+ language::Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "123456")
+ });
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));
@@ -225,7 +228,8 @@ fn test_ime_composition(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let buffer = cx.new_model(|cx| {
- let mut buffer = language::Buffer::new(0, cx.entity_id().as_u64(), "abcde");
+ let mut buffer =
+ language::Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcde");
// Ensure automatic grouping doesn't occur.
buffer.set_group_interval(Duration::ZERO);
buffer
@@ -629,7 +633,7 @@ async fn test_navigation_history(cx: &mut TestAppContext) {
// Ensure we don't panic when navigation data contains invalid anchors *and* points.
let mut invalid_anchor = editor.scroll_manager.anchor().anchor;
- invalid_anchor.text_anchor.buffer_id = Some(999);
+ invalid_anchor.text_anchor.buffer_id = BufferId::new(999).ok();
let invalid_point = Point::new(9999, 0);
editor.navigate(
Box::new(NavigationData {
@@ -2342,11 +2346,20 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) {
));
let toml_buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), "a = 1\nb = 2\n").with_language(toml_language, cx)
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ "a = 1\nb = 2\n",
+ )
+ .with_language(toml_language, cx)
});
let rust_buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), "const c: usize = 3;\n")
- .with_language(rust_language, cx)
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ "const c: usize = 3;\n",
+ )
+ .with_language(rust_language, cx)
});
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
@@ -3984,8 +3997,10 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) {
"#
.unindent();
- let buffer = cx
- .new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx));
+ 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| MultiBuffer::singleton(buffer, cx));
let (view, cx) = cx.add_window_view(|cx| build_editor(buffer, cx));
@@ -4149,8 +4164,10 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) {
let text = "fn a() {}";
- let buffer = cx
- .new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx));
+ 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| MultiBuffer::singleton(buffer, cx));
let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx));
editor
@@ -4713,8 +4730,10 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) {
"#
.unindent();
- let buffer = cx
- .new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx));
+ 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| 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))
@@ -4862,8 +4881,10 @@ async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) {
"#
.unindent();
- let buffer = cx
- .new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx));
+ 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| MultiBuffer::singleton(buffer, cx));
let (editor, cx) = cx.add_window_view(|cx| build_editor(buffer, cx));
editor
@@ -6095,7 +6116,13 @@ 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, cx.entity_id().as_u64(), sample_text(3, 4, 'a')));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ sample_text(3, 4, 'a'),
+ )
+ });
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(
@@ -6179,7 +6206,13 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) {
primary: None,
}
});
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), initial_text));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ initial_text,
+ )
+ });
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(buffer, excerpt_ranges, cx);
@@ -6237,7 +6270,13 @@ 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, cx.entity_id().as_u64(), sample_text(3, 4, 'a')));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ sample_text(3, 4, 'a'),
+ )
+ });
let mut excerpt1_id = None;
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
@@ -6322,7 +6361,13 @@ 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, cx.entity_id().as_u64(), sample_text(3, 4, 'a')));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ sample_text(3, 4, 'a'),
+ )
+ });
let mut excerpt1_id = None;
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
@@ -6417,8 +6462,10 @@ async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
"{{} }\n", //
);
- let buffer = cx
- .new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx));
+ 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| 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))
@@ -7498,8 +7545,20 @@ async fn test_copilot_multibuffer(executor: BackgroundExecutor, cx: &mut gpui::T
let (copilot, copilot_lsp) = Copilot::fake(cx);
_ = cx.update(|cx| cx.set_global(copilot));
- let buffer_1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "a = 1\nb = 2\n"));
- let buffer_2 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "c = 3\nd = 4\n"));
+ let buffer_1 = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ "a = 1\nb = 2\n",
+ )
+ });
+ let buffer_2 = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ "c = 3\nd = 4\n",
+ )
+ });
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(
@@ -28,7 +28,7 @@ use collections::{hash_map, HashMap, HashSet};
use language::language_settings::InlayHintSettings;
use smol::lock::Semaphore;
use sum_tree::Bias;
-use text::{ToOffset, ToPoint};
+use text::{BufferId, ToOffset, ToPoint};
use util::post_inc;
pub struct InlayHintCache {
@@ -50,7 +50,7 @@ struct TasksForRanges {
struct CachedExcerptHints {
version: usize,
buffer_version: Global,
- buffer_id: u64,
+ buffer_id: BufferId,
ordered_hints: Vec<InlayId>,
hints_by_id: HashMap<InlayId, InlayHint>,
}
@@ -93,7 +93,7 @@ struct ExcerptHintsUpdate {
#[derive(Debug, Clone, Copy)]
struct ExcerptQuery {
- buffer_id: u64,
+ buffer_id: BufferId,
excerpt_id: ExcerptId,
cache_version: usize,
invalidate: InvalidationStrategy,
@@ -553,7 +553,7 @@ impl InlayHintCache {
/// Queries a certain hint from the cache for extra data via the LSP <a href="https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHint_resolve">resolve</a> request.
pub(super) fn spawn_hint_resolve(
&self,
- buffer_id: u64,
+ buffer_id: BufferId,
excerpt_id: ExcerptId,
id: InlayId,
cx: &mut ViewContext<'_, Editor>,
@@ -30,7 +30,7 @@ use std::{
path::{Path, PathBuf},
sync::Arc,
};
-use text::Selection;
+use text::{BufferId, Selection};
use theme::Theme;
use ui::{h_flex, prelude::*, Label};
use util::{paths::PathExt, paths::FILE_ROW_COLUMN_DELIMITER, ResultExt, TryFutureExt};
@@ -73,12 +73,14 @@ impl FollowableItem for Editor {
.iter()
.map(|excerpt| excerpt.buffer_id)
.collect::<HashSet<_>>();
- let buffers = project.update(cx, |project, cx| {
- buffer_ids
- .iter()
- .map(|id| project.open_buffer_by_id(*id, cx))
- .collect::<Vec<_>>()
- });
+ let buffers = project
+ .update(cx, |project, cx| {
+ buffer_ids
+ .iter()
+ .map(|id| BufferId::new(*id).map(|id| project.open_buffer_by_id(id, cx)))
+ .collect::<Result<Vec<_>>>()
+ })
+ .ok()?;
let pane = pane.downgrade();
Some(cx.spawn(|mut cx| async move {
@@ -109,10 +111,12 @@ impl FollowableItem for Editor {
MultiBuffer::new(replica_id, project.read(cx).capability());
let mut excerpts = state.excerpts.into_iter().peekable();
while let Some(excerpt) = excerpts.peek() {
- let buffer_id = excerpt.buffer_id;
+ let Ok(buffer_id) = BufferId::new(excerpt.buffer_id) else {
+ continue;
+ };
let buffer_excerpts = iter::from_fn(|| {
let excerpt = excerpts.peek()?;
- (excerpt.buffer_id == buffer_id)
+ (excerpt.buffer_id == u64::from(buffer_id))
.then(|| excerpts.next().unwrap())
});
let buffer =
@@ -189,7 +193,7 @@ impl FollowableItem for Editor {
.excerpts()
.map(|(id, buffer, range)| proto::Excerpt {
id: id.to_proto(),
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
context_start: Some(serialize_text_anchor(&range.context.start)),
context_end: Some(serialize_text_anchor(&range.context.end)),
primary_start: range
@@ -336,9 +340,9 @@ async fn update_editor_from_message(
let inserted_excerpt_buffers = project.update(cx, |project, cx| {
inserted_excerpt_buffer_ids
.into_iter()
- .map(|id| project.open_buffer_by_id(id, cx))
- .collect::<Vec<_>>()
- })?;
+ .map(|id| BufferId::new(id).map(|id| project.open_buffer_by_id(id, cx)))
+ .collect::<Result<Vec<_>>>()
+ })??;
let _inserted_excerpt_buffers = try_join_all(inserted_excerpt_buffers).await?;
// Update the editor's excerpts.
@@ -362,7 +366,7 @@ async fn update_editor_from_message(
let Some(previous_excerpt_id) = insertion.previous_excerpt_id else {
continue;
};
- let buffer_id = excerpt.buffer_id;
+ let buffer_id = BufferId::new(excerpt.buffer_id)?;
let Some(buffer) = project.read(cx).buffer_for_id(buffer_id) else {
continue;
};
@@ -370,7 +374,7 @@ async fn update_editor_from_message(
let adjacent_excerpts = iter::from_fn(|| {
let insertion = insertions.peek()?;
if insertion.previous_excerpt_id.is_none()
- && insertion.excerpt.as_ref()?.buffer_id == buffer_id
+ && insertion.excerpt.as_ref()?.buffer_id == u64::from(buffer_id)
{
insertions.next()?.excerpt
} else {
@@ -395,8 +399,9 @@ async fn update_editor_from_message(
}
multibuffer.remove_excerpts(removed_excerpt_ids, cx);
- });
- })?;
+ Result::<(), anyhow::Error>::Ok(())
+ })
+ })??;
// Deserialize the editor state.
let (selections, pending_selection, scroll_top_anchor) = this.update(cx, |editor, cx| {
@@ -450,13 +455,13 @@ async fn update_editor_from_message(
}
fn serialize_excerpt(
- buffer_id: u64,
+ buffer_id: BufferId,
id: &ExcerptId,
range: &ExcerptRange<language::Anchor>,
) -> Option<proto::Excerpt> {
Some(proto::Excerpt {
id: id.to_proto(),
- buffer_id,
+ buffer_id: buffer_id.into(),
context_start: Some(serialize_text_anchor(&range.context.start)),
context_end: Some(serialize_text_anchor(&range.context.end)),
primary_start: range
@@ -522,6 +522,7 @@ mod tests {
use language::Capability;
use project::Project;
use settings::SettingsStore;
+ use text::BufferId;
use util::post_inc;
#[gpui::test]
@@ -822,8 +823,13 @@ mod tests {
let font = font("Helvetica");
- let buffer =
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abc\ndefg\nhijkl\nmn"));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ "abc\ndefg\nhijkl\nmn",
+ )
+ });
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, Capability::ReadWrite);
multibuffer.push_excerpts(
@@ -314,7 +314,7 @@ mod tests {
use std::assert_eq;
use super::*;
- use text::Buffer;
+ use text::{Buffer, BufferId};
use unindent::Unindent as _;
#[test]
@@ -333,7 +333,7 @@ mod tests {
"
.unindent();
- let mut buffer = Buffer::new(0, 0, buffer_text);
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), buffer_text);
let mut diff = BufferDiff::new();
smol::block_on(diff.update(&diff_base, &buffer));
assert_hunks(
@@ -393,7 +393,7 @@ mod tests {
"
.unindent();
- let buffer = Buffer::new(0, 0, buffer_text);
+ let buffer = Buffer::new(0, BufferId::new(1).unwrap(), buffer_text);
let mut diff = BufferDiff::new();
smol::block_on(diff.update(&diff_base, &buffer));
assert_eq!(diff.hunks(&buffer).count(), 8);
@@ -15,7 +15,7 @@ use crate::{
},
CodeLabel, LanguageScope, Outline,
};
-use anyhow::{anyhow, Result};
+use anyhow::{anyhow, Context, Result};
pub use clock::ReplicaId;
use futures::channel::oneshot;
use gpui::{AppContext, EventEmitter, HighlightStyle, ModelContext, Task, TaskLabel};
@@ -44,10 +44,10 @@ use sum_tree::TreeMap;
use text::operation_queue::OperationQueue;
use text::*;
pub use text::{
- Anchor, Bias, Buffer as TextBuffer, BufferSnapshot as TextBufferSnapshot, Edit, OffsetRangeExt,
- OffsetUtf16, Patch, Point, PointUtf16, Rope, RopeFingerprint, Selection, SelectionGoal,
- Subscription, TextDimension, TextSummary, ToOffset, ToOffsetUtf16, ToPoint, ToPointUtf16,
- Transaction, TransactionId, Unclipped,
+ Anchor, Bias, Buffer as TextBuffer, BufferId, BufferSnapshot as TextBufferSnapshot, Edit,
+ OffsetRangeExt, OffsetUtf16, Patch, Point, PointUtf16, Rope, RopeFingerprint, Selection,
+ SelectionGoal, Subscription, TextDimension, TextSummary, ToOffset, ToOffsetUtf16, ToPoint,
+ ToPointUtf16, Transaction, TransactionId, Unclipped,
};
use theme::SyntaxTheme;
#[cfg(any(test, feature = "test-support"))]
@@ -396,7 +396,7 @@ pub trait LocalFile: File {
/// Called when the buffer is reloaded from disk.
fn buffer_reloaded(
&self,
- buffer_id: u64,
+ buffer_id: BufferId,
version: &clock::Global,
fingerprint: RopeFingerprint,
line_ending: LineEnding,
@@ -517,7 +517,7 @@ pub enum CharKind {
impl Buffer {
/// Create a new buffer with the given base text.
- pub fn new<T: Into<String>>(replica_id: ReplicaId, id: u64, base_text: T) -> Self {
+ pub fn new<T: Into<String>>(replica_id: ReplicaId, id: BufferId, base_text: T) -> Self {
Self::build(
TextBuffer::new(replica_id, id, base_text.into()),
None,
@@ -528,7 +528,7 @@ impl Buffer {
/// Create a new buffer that is a replica of a remote buffer.
pub fn remote(
- remote_id: u64,
+ remote_id: BufferId,
replica_id: ReplicaId,
capability: Capability,
base_text: String,
@@ -549,7 +549,9 @@ impl Buffer {
message: proto::BufferState,
file: Option<Arc<dyn File>>,
) -> Result<Self> {
- let buffer = TextBuffer::new(replica_id, message.id, message.base_text);
+ let buffer_id = BufferId::new(message.id)
+ .with_context(|| anyhow!("Could not deserialize buffer_id"))?;
+ let buffer = TextBuffer::new(replica_id, buffer_id, message.base_text);
let mut this = Self::build(
buffer,
message.diff_base.map(|text| text.into_boxed_str().into()),
@@ -572,7 +574,7 @@ impl Buffer {
/// Serialize the buffer's state to a protobuf message.
pub fn to_proto(&self) -> proto::BufferState {
proto::BufferState {
- id: self.remote_id(),
+ id: self.remote_id().into(),
file: self.file.as_ref().map(|f| f.to_proto()),
base_text: self.base_text().to_string(),
diff_base: self.diff_base.as_ref().map(|h| h.to_string()),
@@ -18,7 +18,7 @@ use std::{
time::{Duration, Instant},
};
use text::network::Network;
-use text::LineEnding;
+use text::{BufferId, LineEnding};
use text::{Point, ToPoint};
use unindent::Unindent as _;
use util::{assert_set_eq, post_inc, test::marked_text_ranges, RandomCharIter};
@@ -43,8 +43,12 @@ fn test_line_endings(cx: &mut gpui::AppContext) {
init_settings(cx, |_| {});
cx.new_model(|cx| {
- let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "one\r\ntwo\rthree")
- .with_language(Arc::new(rust_lang()), cx);
+ let mut buffer = Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ "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 +142,10 @@ fn test_edit_events(cx: &mut gpui::AppContext) {
let buffer_1_events = Arc::new(Mutex::new(Vec::new()));
let buffer_2_events = Arc::new(Mutex::new(Vec::new()));
- let buffer1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcdef"));
- let buffer2 = cx.new_model(|cx| Buffer::new(1, cx.entity_id().as_u64(), "abcdef"));
+ let buffer1 = cx
+ .new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcdef"));
+ let buffer2 = cx
+ .new_model(|cx| Buffer::new(1, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcdef"));
let buffer1_ops = Arc::new(Mutex::new(Vec::new()));
buffer1.update(cx, {
let buffer1_ops = buffer1_ops.clone();
@@ -218,7 +224,8 @@ fn test_edit_events(cx: &mut gpui::AppContext) {
#[gpui::test]
async fn test_apply_diff(cx: &mut TestAppContext) {
let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
+ let buffer =
+ cx.new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text));
let anchor = buffer.update(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
let text = "a\nccc\ndddd\nffffff\n";
@@ -250,7 +257,8 @@ async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
]
.join("\n");
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
+ let buffer =
+ cx.new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text));
// Spawn a task to format the buffer's whitespace.
// Pause so that the foratting task starts running.
@@ -315,7 +323,8 @@ async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
async fn test_reparse(cx: &mut gpui::TestAppContext) {
let text = "fn a() {}";
let buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(Arc::new(rust_lang()), cx)
});
// Wait for the initial text to parse
@@ -443,8 +452,8 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
#[gpui::test]
async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
let buffer = cx.new_model(|cx| {
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), "{}").with_language(Arc::new(rust_lang()), cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "{}")
+ .with_language(Arc::new(rust_lang()), cx);
buffer.set_sync_parse_timeout(Duration::ZERO);
buffer
});
@@ -493,7 +502,8 @@ async fn test_outline(cx: &mut gpui::TestAppContext) {
.unindent();
let buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(Arc::new(rust_lang()), cx)
});
let outline = buffer
.update(cx, |buffer, _| buffer.snapshot().outline(None))
@@ -579,7 +589,8 @@ async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) {
.unindent();
let buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(Arc::new(rust_lang()), cx)
});
let outline = buffer
.update(cx, |buffer, _| buffer.snapshot().outline(None))
@@ -617,7 +628,8 @@ async fn test_outline_with_extra_context(cx: &mut gpui::TestAppContext) {
.unindent();
let buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(language), cx)
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(Arc::new(language), cx)
});
let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
@@ -661,7 +673,8 @@ async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
.unindent();
let buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(Arc::new(rust_lang()), cx)
});
let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
@@ -883,8 +896,8 @@ fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &
fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
cx.new_model(|cx| {
let text = "fn a() { b(|c| {}) }";
- let buffer =
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
+ let buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(Arc::new(rust_lang()), cx);
let snapshot = buffer.snapshot();
assert_eq!(
@@ -924,8 +937,8 @@ fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
cx.new_model(|cx| {
let text = "fn a() {}";
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), 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}");
@@ -967,8 +980,8 @@ fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
cx.new_model(|cx| {
let text = "fn a() {}";
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), 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}");
@@ -1007,10 +1020,9 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppC
init_settings(cx, |_| {});
cx.new_model(|cx| {
- let entity_id = cx.entity_id();
let mut buffer = Buffer::new(
0,
- entity_id.as_u64(),
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
"
fn a() {
c;
@@ -1085,7 +1097,7 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppC
let mut buffer = Buffer::new(
0,
- cx.entity_id().as_u64(),
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
"
fn a() {
b();
@@ -1150,7 +1162,7 @@ fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut Ap
cx.new_model(|cx| {
let mut buffer = Buffer::new(
0,
- cx.entity_id().as_u64(),
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
"
fn a() {
i
@@ -1212,7 +1224,7 @@ fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
cx.new_model(|cx| {
let mut buffer = Buffer::new(
0,
- cx.entity_id().as_u64(),
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
"
fn a() {}
"
@@ -1268,8 +1280,8 @@ fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
cx.new_model(|cx| {
let text = "a\nb";
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(Arc::new(rust_lang()), cx);
buffer.edit(
[(0..1, "\n"), (2..3, "\n")],
Some(AutoindentMode::EachLine),
@@ -1295,8 +1307,8 @@ fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
"
.unindent();
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), 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),
@@ -1333,8 +1345,8 @@ fn test_autoindent_block_mode(cx: &mut AppContext) {
}
"#
.unindent();
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), 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
@@ -1419,8 +1431,8 @@ fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContex
}
"#
.unindent();
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), 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
@@ -1499,17 +1511,18 @@ fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
"
.unindent();
- let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), text).with_language(
- Arc::new(Language::new(
- LanguageConfig {
- name: "Markdown".into(),
- auto_indent_using_last_non_empty_line: false,
- ..Default::default()
- },
- Some(tree_sitter_json::language()),
- )),
- cx,
- );
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(
+ Arc::new(Language::new(
+ LanguageConfig {
+ name: "Markdown".into(),
+ auto_indent_using_last_non_empty_line: false,
+ ..Default::default()
+ },
+ Some(tree_sitter_json::language()),
+ )),
+ cx,
+ );
buffer.edit(
[(Point::new(3, 0)..Point::new(3, 0), "\n")],
Some(AutoindentMode::EachLine),
@@ -1575,7 +1588,7 @@ fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
false,
);
- let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), text);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text);
buffer.set_language_registry(language_registry);
buffer.set_language(Some(html_language), cx);
buffer.edit(
@@ -1611,8 +1624,8 @@ fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
});
cx.new_model(|cx| {
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), "").with_language(Arc::new(ruby_lang()), cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "")
+ .with_language(Arc::new(ruby_lang()), cx);
let text = r#"
class C
@@ -1713,8 +1726,8 @@ fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
"#
.unindent();
- let buffer =
- Buffer::new(0, cx.entity_id().as_u64(), &text).with_language(Arc::new(language), cx);
+ let buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), &text)
+ .with_language(Arc::new(language), cx);
let snapshot = buffer.snapshot();
let config = snapshot.language_scope_at(0).unwrap();
@@ -1831,8 +1844,12 @@ fn test_language_scope_at_with_rust(cx: &mut AppContext) {
"#
.unindent();
- let buffer = Buffer::new(0, cx.entity_id().as_u64(), text.clone())
- .with_language(Arc::new(language), cx);
+ let buffer = Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ text.clone(),
+ )
+ .with_language(Arc::new(language), cx);
let snapshot = buffer.snapshot();
// By default, all brackets are enabled
@@ -1876,7 +1893,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, cx.entity_id().as_u64(), text);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text);
buffer.set_language_registry(language_registry.clone());
buffer.set_language(
language_registry
@@ -1911,7 +1928,7 @@ fn test_serialization(cx: &mut gpui::AppContext) {
let mut now = Instant::now();
let buffer1 = cx.new_model(|cx| {
- let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "abc");
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abc");
buffer.edit([(3..3, "D")], None, cx);
now += Duration::from_secs(1);
@@ -1966,8 +1983,13 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
let mut replica_ids = Vec::new();
let mut buffers = Vec::new();
let network = Arc::new(Mutex::new(Network::new(rng.clone())));
- let base_buffer =
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), base_text.as_str()));
+ let base_buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ base_text.as_str(),
+ )
+ });
for i in 0..rng.gen_range(min_peers..=max_peers) {
let buffer = cx.new_model(|cx| {
@@ -2475,8 +2497,12 @@ fn assert_bracket_pairs(
) {
let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
let buffer = cx.new_model(|cx| {
- Buffer::new(0, cx.entity_id().as_u64(), expected_text.clone())
- .with_language(Arc::new(language), cx)
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ expected_text.clone(),
+ )
+ .with_language(Arc::new(language), cx)
});
let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
@@ -241,7 +241,7 @@ pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
Bias::Left => proto::Bias::Left as i32,
Bias::Right => proto::Bias::Right as i32,
},
- buffer_id: anchor.buffer_id,
+ buffer_id: anchor.buffer_id.map(Into::into),
}
}
@@ -420,6 +420,11 @@ pub fn deserialize_diagnostics(
/// Deserializes an [`Anchor`] from the RPC representation.
pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
+ let buffer_id = if let Some(id) = anchor.buffer_id {
+ Some(BufferId::new(id).ok()?)
+ } else {
+ None
+ };
Some(Anchor {
timestamp: clock::Lamport {
replica_id: anchor.replica_id as ReplicaId,
@@ -430,7 +435,7 @@ pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
proto::Bias::Left => Bias::Left,
proto::Bias::Right => Bias::Right,
},
- buffer_id: anchor.buffer_id,
+ buffer_id,
})
}
@@ -2,7 +2,7 @@ use super::*;
use crate::LanguageConfig;
use rand::rngs::StdRng;
use std::{env, ops::Range, sync::Arc};
-use text::Buffer;
+use text::{Buffer, BufferId};
use tree_sitter::Node;
use unindent::Unindent as _;
use util::test::marked_text_ranges;
@@ -86,7 +86,7 @@ fn test_syntax_map_layers_for_range() {
let mut buffer = Buffer::new(
0,
- 0,
+ BufferId::new(1).unwrap(),
r#"
fn a() {
assert_eq!(
@@ -185,7 +185,7 @@ fn test_dynamic_language_injection() {
let mut buffer = Buffer::new(
0,
- 0,
+ BufferId::new(1).unwrap(),
r#"
This is a code block:
@@ -860,7 +860,7 @@ fn test_random_edits(
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(10);
- let mut buffer = Buffer::new(0, 0, text);
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), text);
let mut syntax_map = SyntaxMap::new();
syntax_map.set_language_registry(registry.clone());
@@ -1040,7 +1040,7 @@ fn test_edit_sequence(language_name: &str, steps: &[&str]) -> (Buffer, SyntaxMap
.now_or_never()
.unwrap()
.unwrap();
- let mut buffer = Buffer::new(0, 0, Default::default());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), Default::default());
let mut mutated_syntax_map = SyntaxMap::new();
mutated_syntax_map.set_language_registry(registry.clone());
@@ -5,10 +5,11 @@ use std::{
ops::{Range, Sub},
};
use sum_tree::Bias;
+use text::BufferId;
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
pub struct Anchor {
- pub buffer_id: Option<u64>,
+ pub buffer_id: Option<BufferId>,
pub excerpt_id: ExcerptId,
pub text_anchor: text::Anchor,
}
@@ -33,7 +33,7 @@ use sum_tree::{Bias, Cursor, SumTree};
use text::{
locator::Locator,
subscription::{Subscription, Topic},
- Edit, TextSummary,
+ BufferId, Edit, TextSummary,
};
use theme::SyntaxTheme;
use util::post_inc;
@@ -48,7 +48,7 @@ pub struct ExcerptId(usize);
pub struct MultiBuffer {
snapshot: RefCell<MultiBufferSnapshot>,
- buffers: RefCell<HashMap<u64, BufferState>>,
+ buffers: RefCell<HashMap<BufferId, BufferState>>,
next_excerpt_id: usize,
subscriptions: Topic,
singleton: bool,
@@ -101,7 +101,7 @@ struct History {
#[derive(Clone)]
struct Transaction {
id: TransactionId,
- buffer_transactions: HashMap<u64, text::TransactionId>,
+ buffer_transactions: HashMap<BufferId, text::TransactionId>,
first_edit_at: Instant,
last_edit_at: Instant,
suppress_grouping: bool,
@@ -161,7 +161,7 @@ pub struct ExcerptBoundary {
struct Excerpt {
id: ExcerptId,
locator: Locator,
- buffer_id: u64,
+ buffer_id: BufferId,
buffer: BufferSnapshot,
range: ExcerptRange<text::Anchor>,
max_buffer_row: u32,
@@ -366,7 +366,7 @@ impl MultiBuffer {
offset: T,
theme: Option<&SyntaxTheme>,
cx: &AppContext,
- ) -> Option<(u64, Vec<OutlineItem<Anchor>>)> {
+ ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
self.read(cx).symbols_containing(offset, theme)
}
@@ -412,7 +412,7 @@ impl MultiBuffer {
is_insertion: bool,
original_indent_column: u32,
}
- let mut buffer_edits: HashMap<u64, Vec<BufferEdit>> = Default::default();
+ let mut buffer_edits: HashMap<BufferId, Vec<BufferEdit>> = Default::default();
let mut edited_excerpt_ids = Vec::new();
let mut cursor = snapshot.excerpts.cursor::<usize>();
for (ix, (range, new_text)) in edits.enumerate() {
@@ -514,7 +514,7 @@ impl MultiBuffer {
// Non-generic part of edit, hoisted out to avoid blowing up LLVM IR.
fn tail(
this: &mut MultiBuffer,
- buffer_edits: HashMap<u64, Vec<BufferEdit>>,
+ buffer_edits: HashMap<BufferId, Vec<BufferEdit>>,
autoindent_mode: Option<AutoindentMode>,
edited_excerpt_ids: Vec<ExcerptId>,
cx: &mut ModelContext<MultiBuffer>,
@@ -720,7 +720,7 @@ impl MultiBuffer {
cursor_shape: CursorShape,
cx: &mut ModelContext<Self>,
) {
- let mut selections_by_buffer: HashMap<u64, Vec<Selection<text::Anchor>>> =
+ let mut selections_by_buffer: HashMap<BufferId, Vec<Selection<text::Anchor>>> =
Default::default();
let snapshot = self.read(cx);
let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>();
@@ -1440,7 +1440,7 @@ impl MultiBuffer {
.collect()
}
- pub fn buffer(&self, buffer_id: u64) -> Option<Model<Buffer>> {
+ pub fn buffer(&self, buffer_id: BufferId) -> Option<Model<Buffer>> {
self.buffers
.borrow()
.get(&buffer_id)
@@ -1661,7 +1661,8 @@ impl MultiBuffer {
#[cfg(any(test, feature = "test-support"))]
impl MultiBuffer {
pub fn build_simple(text: &str, cx: &mut gpui::AppContext) -> Model<Self> {
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
+ let buffer = cx
+ .new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text));
cx.new_model(|cx| Self::singleton(buffer, cx))
}
@@ -1671,7 +1672,9 @@ impl MultiBuffer {
) -> Model<Self> {
let multi = cx.new_model(|_| Self::new(0, Capability::ReadWrite));
for (text, ranges) in excerpts {
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ });
let excerpt_ranges = ranges.into_iter().map(|range| ExcerptRange {
context: range,
primary: None,
@@ -1760,7 +1763,9 @@ 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.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text)));
+ buffers.push(cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ }));
let buffer = buffers.last().unwrap().read(cx);
log::info!(
"Creating new buffer {} with text: {:?}",
@@ -1987,7 +1992,7 @@ impl MultiBufferSnapshot {
(start..end, word_kind)
}
- pub fn as_singleton(&self) -> Option<(&ExcerptId, u64, &BufferSnapshot)> {
+ pub fn as_singleton(&self) -> Option<(&ExcerptId, BufferId, &BufferSnapshot)> {
if self.singleton {
self.excerpts
.iter()
@@ -3209,7 +3214,7 @@ impl MultiBufferSnapshot {
&self,
offset: T,
theme: Option<&SyntaxTheme>,
- ) -> Option<(u64, Vec<OutlineItem<Anchor>>)> {
+ ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
let anchor = self.anchor_before(offset);
let excerpt_id = anchor.excerpt_id;
let excerpt = self.excerpt(excerpt_id)?;
@@ -3249,7 +3254,7 @@ impl MultiBufferSnapshot {
}
}
- pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<u64> {
+ pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<BufferId> {
Some(self.excerpt(excerpt_id)?.buffer_id)
}
@@ -3387,7 +3392,7 @@ impl History {
fn end_transaction(
&mut self,
now: Instant,
- buffer_transactions: HashMap<u64, TransactionId>,
+ buffer_transactions: HashMap<BufferId, TransactionId>,
) -> bool {
assert_ne!(self.transaction_depth, 0);
self.transaction_depth -= 1;
@@ -3561,7 +3566,7 @@ impl Excerpt {
fn new(
id: ExcerptId,
locator: Locator,
- buffer_id: u64,
+ buffer_id: BufferId,
buffer: BufferSnapshot,
range: ExcerptRange<text::Anchor>,
has_trailing_newline: bool,
@@ -4154,8 +4159,13 @@ mod tests {
#[gpui::test]
fn test_singleton(cx: &mut AppContext) {
- let buffer =
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(6, 6, 'a')));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ sample_text(6, 6, 'a'),
+ )
+ });
let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
let snapshot = multibuffer.read(cx).snapshot(cx);
@@ -4182,7 +4192,8 @@ mod tests {
#[gpui::test]
fn test_remote(cx: &mut AppContext) {
- let host_buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "a"));
+ let host_buffer =
+ cx.new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "a"));
let guest_buffer = cx.new_model(|cx| {
let state = host_buffer.read(cx).to_proto();
let ops = cx
@@ -4213,10 +4224,20 @@ mod tests {
#[gpui::test]
fn test_excerpt_boundaries_and_clipping(cx: &mut AppContext) {
- let buffer_1 =
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(6, 6, 'a')));
- let buffer_2 =
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(6, 6, 'g')));
+ let buffer_1 = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ sample_text(6, 6, 'a'),
+ )
+ });
+ let buffer_2 = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ sample_text(6, 6, 'g'),
+ )
+ });
let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let events = Arc::new(RwLock::new(Vec::<Event>::new()));
@@ -4449,10 +4470,20 @@ mod tests {
#[gpui::test]
fn test_excerpt_events(cx: &mut AppContext) {
- let buffer_1 =
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(10, 3, 'a')));
- let buffer_2 =
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(10, 3, 'm')));
+ let buffer_1 = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ sample_text(10, 3, 'a'),
+ )
+ });
+ let buffer_2 = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ sample_text(10, 3, 'm'),
+ )
+ });
let leader_multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let follower_multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
@@ -4557,8 +4588,13 @@ mod tests {
#[gpui::test]
fn test_push_excerpts_with_context_lines(cx: &mut AppContext) {
- let buffer =
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(20, 3, 'a')));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ sample_text(20, 3, 'a'),
+ )
+ });
let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
multibuffer.push_excerpts_with_context_lines(
@@ -4594,8 +4630,13 @@ mod tests {
#[gpui::test]
async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) {
- let buffer =
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(20, 3, 'a')));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ sample_text(20, 3, 'a'),
+ )
+ });
let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
let snapshot = buffer.read(cx);
@@ -4641,7 +4682,9 @@ mod tests {
#[gpui::test]
fn test_singleton_multibuffer_anchors(cx: &mut AppContext) {
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcd"));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcd")
+ });
let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
let old_snapshot = multibuffer.read(cx).snapshot(cx);
buffer.update(cx, |buffer, cx| {
@@ -4661,8 +4704,12 @@ mod tests {
#[gpui::test]
fn test_multibuffer_anchors(cx: &mut AppContext) {
- let buffer_1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcd"));
- let buffer_2 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "efghi"));
+ let buffer_1 = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcd")
+ });
+ let buffer_2 = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "efghi")
+ });
let multibuffer = cx.new_model(|cx| {
let mut multibuffer = MultiBuffer::new(0, Capability::ReadWrite);
multibuffer.push_excerpts(
@@ -4719,9 +4766,16 @@ mod tests {
#[gpui::test]
fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut AppContext) {
- let buffer_1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcd"));
- let buffer_2 =
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "ABCDEFGHIJKLMNOP"));
+ let buffer_1 = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcd")
+ });
+ let buffer_2 = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ "ABCDEFGHIJKLMNOP",
+ )
+ });
let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
// Create an insertion id in buffer 1 that doesn't exist in buffer 2.
@@ -4932,9 +4986,13 @@ mod tests {
let base_text = util::RandomCharIter::new(&mut rng)
.take(10)
.collect::<String>();
- buffers.push(
- cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), base_text)),
- );
+ buffers.push(cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ base_text,
+ )
+ }));
buffers.last().unwrap()
} else {
buffers.choose(&mut rng).unwrap()
@@ -5276,8 +5334,12 @@ mod tests {
let test_settings = SettingsStore::test(cx);
cx.set_global(test_settings);
- let buffer_1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "1234"));
- let buffer_2 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "5678"));
+ let buffer_1 = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "1234")
+ });
+ let buffer_2 = cx.new_model(|cx| {
+ Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "5678")
+ });
let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let group_interval = multibuffer.read(cx).history.group_interval;
multibuffer.update(cx, |multibuffer, cx| {
@@ -21,7 +21,7 @@ use lsp::{
OneOf, ServerCapabilities,
};
use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
-use text::LineEnding;
+use text::{BufferId, LineEnding};
pub fn lsp_formatting_options(tab_size: u32) -> lsp::FormattingOptions {
lsp::FormattingOptions {
@@ -84,7 +84,7 @@ pub trait LspCommand: 'static + Sized + Send {
cx: AsyncAppContext,
) -> Result<Self::Response>;
- fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64;
+ fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId>;
}
pub(crate) struct PrepareRename {
@@ -205,7 +205,7 @@ impl LspCommand for PrepareRename {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {
proto::PrepareRename {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
position: Some(language::proto::serialize_anchor(
&buffer.anchor_before(self.position),
)),
@@ -274,8 +274,8 @@ impl LspCommand for PrepareRename {
}
}
- fn buffer_id_from_proto(message: &proto::PrepareRename) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::PrepareRename) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -332,7 +332,7 @@ impl LspCommand for PerformRename {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {
proto::PerformRename {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
position: Some(language::proto::serialize_anchor(
&buffer.anchor_before(self.position),
)),
@@ -393,8 +393,8 @@ impl LspCommand for PerformRename {
.await
}
- fn buffer_id_from_proto(message: &proto::PerformRename) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::PerformRename) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -437,7 +437,7 @@ impl LspCommand for GetDefinition {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
proto::GetDefinition {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
position: Some(language::proto::serialize_anchor(
&buffer.anchor_before(self.position),
)),
@@ -486,8 +486,8 @@ impl LspCommand for GetDefinition {
location_links_from_proto(message.links, project, cx).await
}
- fn buffer_id_from_proto(message: &proto::GetDefinition) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::GetDefinition) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -538,7 +538,7 @@ impl LspCommand for GetTypeDefinition {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
proto::GetTypeDefinition {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
position: Some(language::proto::serialize_anchor(
&buffer.anchor_before(self.position),
)),
@@ -587,8 +587,8 @@ impl LspCommand for GetTypeDefinition {
location_links_from_proto(message.links, project, cx).await
}
- fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -617,9 +617,10 @@ async fn location_links_from_proto(
for link in proto_links {
let origin = match link.origin {
Some(origin) => {
+ let buffer_id = BufferId::new(origin.buffer_id)?;
let buffer = project
.update(&mut cx, |this, cx| {
- this.wait_for_remote_buffer(origin.buffer_id, cx)
+ this.wait_for_remote_buffer(buffer_id, cx)
})?
.await?;
let start = origin
@@ -642,9 +643,10 @@ async fn location_links_from_proto(
};
let target = link.target.ok_or_else(|| anyhow!("missing target"))?;
+ let buffer_id = BufferId::new(target.buffer_id)?;
let buffer = project
.update(&mut cx, |this, cx| {
- this.wait_for_remote_buffer(target.buffer_id, cx)
+ this.wait_for_remote_buffer(buffer_id, cx)
})?
.await?;
let start = target
@@ -761,7 +763,9 @@ fn location_links_to_proto(
.into_iter()
.map(|definition| {
let origin = definition.origin.map(|origin| {
- let buffer_id = project.create_buffer_for_peer(&origin.buffer, peer_id, cx);
+ let buffer_id = project
+ .create_buffer_for_peer(&origin.buffer, peer_id, cx)
+ .into();
proto::Location {
start: Some(serialize_anchor(&origin.range.start)),
end: Some(serialize_anchor(&origin.range.end)),
@@ -769,7 +773,9 @@ fn location_links_to_proto(
}
});
- let buffer_id = project.create_buffer_for_peer(&definition.target.buffer, peer_id, cx);
+ let buffer_id = project
+ .create_buffer_for_peer(&definition.target.buffer, peer_id, cx)
+ .into();
let target = proto::Location {
start: Some(serialize_anchor(&definition.target.range.start)),
end: Some(serialize_anchor(&definition.target.range.end)),
@@ -859,7 +865,7 @@ impl LspCommand for GetReferences {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
proto::GetReferences {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
position: Some(language::proto::serialize_anchor(
&buffer.anchor_before(self.position),
)),
@@ -901,7 +907,7 @@ impl LspCommand for GetReferences {
proto::Location {
start: Some(serialize_anchor(&definition.range.start)),
end: Some(serialize_anchor(&definition.range.end)),
- buffer_id,
+ buffer_id: buffer_id.into(),
}
})
.collect();
@@ -917,9 +923,10 @@ impl LspCommand for GetReferences {
) -> Result<Vec<Location>> {
let mut locations = Vec::new();
for location in message.locations {
+ let buffer_id = BufferId::new(location.buffer_id)?;
let target_buffer = project
.update(&mut cx, |this, cx| {
- this.wait_for_remote_buffer(location.buffer_id, cx)
+ this.wait_for_remote_buffer(buffer_id, cx)
})?
.await?;
let start = location
@@ -941,8 +948,8 @@ impl LspCommand for GetReferences {
Ok(locations)
}
- fn buffer_id_from_proto(message: &proto::GetReferences) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::GetReferences) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -1007,7 +1014,7 @@ impl LspCommand for GetDocumentHighlights {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
proto::GetDocumentHighlights {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
position: Some(language::proto::serialize_anchor(
&buffer.anchor_before(self.position),
)),
@@ -1092,8 +1099,8 @@ impl LspCommand for GetDocumentHighlights {
Ok(highlights)
}
- fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -1195,7 +1202,7 @@ impl LspCommand for GetHover {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
proto::GetHover {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
position: Some(language::proto::serialize_anchor(
&buffer.anchor_before(self.position),
)),
@@ -1308,8 +1315,8 @@ impl LspCommand for GetHover {
}))
}
- fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -1492,7 +1499,7 @@ impl LspCommand for GetCompletions {
let anchor = buffer.anchor_after(self.position);
proto::GetCompletions {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
position: Some(language::proto::serialize_anchor(&anchor)),
version: serialize_version(&buffer.version()),
}
@@ -1556,8 +1563,8 @@ impl LspCommand for GetCompletions {
future::try_join_all(completions).await
}
- fn buffer_id_from_proto(message: &proto::GetCompletions) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -1630,7 +1637,7 @@ impl LspCommand for GetCodeActions {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
proto::GetCodeActions {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
start: Some(language::proto::serialize_anchor(&self.range.start)),
end: Some(language::proto::serialize_anchor(&self.range.end)),
version: serialize_version(&buffer.version()),
@@ -1695,8 +1702,8 @@ impl LspCommand for GetCodeActions {
.collect()
}
- fn buffer_id_from_proto(message: &proto::GetCodeActions) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -1768,7 +1775,7 @@ impl LspCommand for OnTypeFormatting {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
proto::OnTypeFormatting {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
position: Some(language::proto::serialize_anchor(
&buffer.anchor_before(self.position),
)),
@@ -1831,8 +1838,8 @@ impl LspCommand for OnTypeFormatting {
Ok(Some(language::proto::deserialize_transaction(transaction)?))
}
- fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -2291,7 +2298,7 @@ impl LspCommand for InlayHints {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
proto::InlayHints {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
start: Some(language::proto::serialize_anchor(&self.range.start)),
end: Some(language::proto::serialize_anchor(&self.range.end)),
version: serialize_version(&buffer.version()),
@@ -2358,7 +2365,7 @@ impl LspCommand for InlayHints {
Ok(hints)
}
- fn buffer_id_from_proto(message: &proto::InlayHints) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -1,13 +1,13 @@
use std::{path::Path, sync::Arc};
-use anyhow::Context;
+use anyhow::{Context, Result};
use async_trait::async_trait;
use gpui::{AppContext, AsyncAppContext, Model};
use language::{point_to_lsp, proto::deserialize_anchor, Buffer};
use lsp::{LanguageServer, LanguageServerId};
use rpc::proto::{self, PeerId};
use serde::{Deserialize, Serialize};
-use text::{PointUtf16, ToPointUtf16};
+use text::{BufferId, PointUtf16, ToPointUtf16};
use crate::{lsp_command::LspCommand, Project};
@@ -83,7 +83,7 @@ impl LspCommand for ExpandMacro {
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LspExtExpandMacro {
proto::LspExtExpandMacro {
project_id,
- buffer_id: buffer.remote_id(),
+ buffer_id: buffer.remote_id().into(),
position: Some(language::proto::serialize_anchor(
&buffer.anchor_before(self.position),
)),
@@ -131,7 +131,7 @@ impl LspCommand for ExpandMacro {
})
}
- fn buffer_id_from_proto(message: &proto::LspExtExpandMacro) -> u64 {
- message.buffer_id
+ fn buffer_id_from_proto(message: &proto::LspExtExpandMacro) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
}
}
@@ -12,7 +12,7 @@ mod project_tests;
#[cfg(test)]
mod worktree_tests;
-use anyhow::{anyhow, Context as _, Result};
+use anyhow::{anyhow, bail, Context as _, Result};
use client::{proto, Client, Collaborator, TypedEnvelope, UserStore};
use clock::ReplicaId;
use collections::{hash_map, BTreeMap, HashMap, HashSet, VecDeque};
@@ -81,7 +81,7 @@ use std::{
time::{Duration, Instant},
};
use terminals::Terminals;
-use text::Anchor;
+use text::{Anchor, BufferId};
use util::{
debug_panic, defer, http::HttpClient, merge_json_value_into,
paths::LOCAL_SETTINGS_RELATIVE_PATH, post_inc, ResultExt, TryFutureExt as _,
@@ -120,9 +120,9 @@ pub struct Project {
collaborators: HashMap<proto::PeerId, Collaborator>,
client_subscriptions: Vec<client::Subscription>,
_subscriptions: Vec<gpui::Subscription>,
- next_buffer_id: u64,
+ next_buffer_id: BufferId,
opened_buffer: (watch::Sender<()>, watch::Receiver<()>),
- shared_buffers: HashMap<proto::PeerId, HashSet<u64>>,
+ shared_buffers: HashMap<proto::PeerId, HashSet<BufferId>>,
#[allow(clippy::type_complexity)]
loading_buffers_by_path: HashMap<
ProjectPath,
@@ -131,14 +131,14 @@ pub struct Project {
#[allow(clippy::type_complexity)]
loading_local_worktrees:
HashMap<Arc<Path>, Shared<Task<Result<Model<Worktree>, Arc<anyhow::Error>>>>>,
- opened_buffers: HashMap<u64, OpenBuffer>,
- local_buffer_ids_by_path: HashMap<ProjectPath, u64>,
- local_buffer_ids_by_entry_id: HashMap<ProjectEntryId, u64>,
+ opened_buffers: HashMap<BufferId, OpenBuffer>,
+ local_buffer_ids_by_path: HashMap<ProjectPath, BufferId>,
+ local_buffer_ids_by_entry_id: HashMap<ProjectEntryId, BufferId>,
/// A mapping from a buffer ID to None means that we've started waiting for an ID but haven't finished loading it.
/// Used for re-issuing buffer requests when peers temporarily disconnect
- incomplete_remote_buffers: HashMap<u64, Option<Model<Buffer>>>,
- buffer_snapshots: HashMap<u64, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
- buffers_being_formatted: HashSet<u64>,
+ incomplete_remote_buffers: HashMap<BufferId, Option<Model<Buffer>>>,
+ buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
+ buffers_being_formatted: HashSet<BufferId>,
buffers_needing_diff: HashSet<WeakModel<Buffer>>,
git_diff_debouncer: DelayedDebounced,
nonce: u128,
@@ -210,7 +210,7 @@ struct LspBufferSnapshot {
/// Message ordered with respect to buffer operations
enum BufferOrderedMessage {
Operation {
- buffer_id: u64,
+ buffer_id: BufferId,
operation: proto::Operation,
},
LanguageServerUpdate {
@@ -224,7 +224,7 @@ enum LocalProjectUpdate {
WorktreesChanged,
CreateBufferForPeer {
peer_id: proto::PeerId,
- buffer_id: u64,
+ buffer_id: BufferId,
},
}
@@ -636,7 +636,7 @@ impl Project {
worktrees: Vec::new(),
buffer_ordered_messages_tx: tx,
collaborators: Default::default(),
- next_buffer_id: 0,
+ next_buffer_id: BufferId::new(1).unwrap(),
opened_buffers: Default::default(),
shared_buffers: Default::default(),
incomplete_remote_buffers: Default::default(),
@@ -722,7 +722,7 @@ impl Project {
worktrees: Vec::new(),
buffer_ordered_messages_tx: tx,
loading_buffers_by_path: Default::default(),
- next_buffer_id: 0,
+ next_buffer_id: BufferId::default(),
opened_buffer: watch::channel(),
shared_buffers: Default::default(),
incomplete_remote_buffers: Default::default(),
@@ -997,7 +997,7 @@ impl Project {
cx.notify();
}
- pub fn buffer_for_id(&self, remote_id: u64) -> Option<Model<Buffer>> {
+ pub fn buffer_for_id(&self, remote_id: BufferId) -> Option<Model<Buffer>> {
self.opened_buffers
.get(&remote_id)
.and_then(|buffer| buffer.upgrade())
@@ -1479,7 +1479,7 @@ impl Project {
variant: Some(
proto::create_buffer_for_peer::Variant::Chunk(
proto::BufferChunk {
- buffer_id,
+ buffer_id: buffer_id.into(),
operations: chunk,
is_last,
},
@@ -1713,7 +1713,7 @@ 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 id = self.next_buffer_id.next();
let buffer = cx.new_model(|cx| {
Buffer::new(self.replica_id(), id, text)
.with_language(language.unwrap_or_else(|| language::PLAIN_TEXT.clone()), cx)
@@ -1814,7 +1814,7 @@ impl Project {
worktree: &Model<Worktree>,
cx: &mut ModelContext<Self>,
) -> Task<Result<Model<Buffer>>> {
- let buffer_id = post_inc(&mut self.next_buffer_id);
+ let buffer_id = self.next_buffer_id.next();
let load_buffer = worktree.update(cx, |worktree, cx| {
let worktree = worktree.as_local_mut().unwrap();
worktree.load_buffer(buffer_id, path, cx)
@@ -1845,8 +1845,9 @@ impl Project {
path: path_string,
})
.await?;
+ let buffer_id = BufferId::new(response.buffer_id)?;
this.update(&mut cx, |this, cx| {
- this.wait_for_remote_buffer(response.buffer_id, cx)
+ this.wait_for_remote_buffer(buffer_id, cx)
})?
.await
})
@@ -1895,7 +1896,7 @@ impl Project {
pub fn open_buffer_by_id(
&mut self,
- id: u64,
+ id: BufferId,
cx: &mut ModelContext<Self>,
) -> Task<Result<Model<Buffer>>> {
if let Some(buffer) = self.buffer_for_id(id) {
@@ -1903,11 +1904,12 @@ impl Project {
} else if self.is_local() {
Task::ready(Err(anyhow!("buffer {} does not exist", id)))
} else if let Some(project_id) = self.remote_id() {
- let request = self
- .client
- .request(proto::OpenBufferById { project_id, id });
+ let request = self.client.request(proto::OpenBufferById {
+ project_id,
+ id: id.into(),
+ });
cx.spawn(move |this, mut cx| async move {
- let buffer_id = request.await?.buffer_id;
+ let buffer_id = BufferId::new(request.await?.buffer_id)?;
this.update(&mut cx, |this, cx| {
this.wait_for_remote_buffer(buffer_id, cx)
})?
@@ -2223,7 +2225,7 @@ impl Project {
let mut operations_by_buffer_id = HashMap::default();
async fn flush_operations(
this: &WeakModel<Project>,
- operations_by_buffer_id: &mut HashMap<u64, Vec<proto::Operation>>,
+ operations_by_buffer_id: &mut HashMap<BufferId, Vec<proto::Operation>>,
needs_resync_with_host: &mut bool,
is_local: bool,
cx: &mut AsyncAppContext,
@@ -2232,7 +2234,7 @@ impl Project {
let request = this.update(cx, |this, _| {
let project_id = this.remote_id()?;
Some(this.client.request(proto::UpdateBuffer {
- buffer_id,
+ buffer_id: buffer_id.into(),
project_id,
operations,
}))
@@ -4078,7 +4080,9 @@ impl Project {
buffer_ids: remote_buffers
.iter()
.filter_map(|buffer| {
- buffer.update(&mut cx, |buffer, _| buffer.remote_id()).ok()
+ buffer
+ .update(&mut cx, |buffer, _| buffer.remote_id().into())
+ .ok()
})
.collect(),
})
@@ -4324,7 +4328,7 @@ impl Project {
buffer_ids: buffers
.iter()
.map(|buffer| {
- buffer.update(&mut cx, |buffer, _| buffer.remote_id())
+ buffer.update(&mut cx, |buffer, _| buffer.remote_id().into())
})
.collect::<Result<_>>()?,
})
@@ -4720,8 +4724,9 @@ impl Project {
});
cx.spawn(move |this, mut cx| async move {
let response = request.await?;
+ let buffer_id = BufferId::new(response.buffer_id)?;
this.update(&mut cx, |this, cx| {
- this.wait_for_remote_buffer(response.buffer_id, cx)
+ this.wait_for_remote_buffer(buffer_id, cx)
})?
.await
})
@@ -5047,7 +5052,7 @@ impl Project {
let response = client
.request(proto::ApplyCompletionAdditionalEdits {
project_id,
- buffer_id,
+ buffer_id: buffer_id.into(),
completion: Some(language::proto::serialize_completion(&completion)),
})
.await?;
@@ -5179,7 +5184,7 @@ impl Project {
let client = self.client.clone();
let request = proto::ApplyCodeAction {
project_id,
- buffer_id: buffer_handle.read(cx).remote_id(),
+ buffer_id: buffer_handle.read(cx).remote_id().into(),
action: Some(language::proto::serialize_code_action(&action)),
};
cx.spawn(move |this, mut cx| async move {
@@ -5242,7 +5247,7 @@ impl Project {
let client = self.client.clone();
let request = proto::OnTypeFormatting {
project_id,
- buffer_id: buffer.read(cx).remote_id(),
+ buffer_id: buffer.read(cx).remote_id().into(),
position: Some(serialize_anchor(&position)),
trigger,
version: serialize_version(&buffer.read(cx).version()),
@@ -5531,7 +5536,7 @@ impl Project {
let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
let range_start = range.start;
let range_end = range.end;
- let buffer_id = buffer.remote_id();
+ let buffer_id = buffer.remote_id().into();
let buffer_version = buffer.version().clone();
let lsp_request = InlayHints { range };
@@ -5624,7 +5629,7 @@ impl Project {
let client = self.client.clone();
let request = proto::ResolveInlayHint {
project_id,
- buffer_id: buffer_handle.read(cx).remote_id(),
+ buffer_id: buffer_handle.read(cx).remote_id().into(),
language_server_id: server_id.0 as u64,
hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
};
@@ -5659,9 +5664,10 @@ impl Project {
let response = request.await?;
let mut result = HashMap::default();
for location in response.locations {
+ let buffer_id = BufferId::new(location.buffer_id)?;
let target_buffer = this
.update(&mut cx, |this, cx| {
- this.wait_for_remote_buffer(location.buffer_id, cx)
+ this.wait_for_remote_buffer(buffer_id, cx)
})?
.await?;
let start = location
@@ -6555,7 +6561,7 @@ impl Project {
self.client
.send(proto::UpdateBufferFile {
project_id,
- buffer_id: buffer_id as u64,
+ buffer_id: buffer_id.into(),
file: Some(new_file.to_proto()),
})
.log_err();
@@ -6721,7 +6727,7 @@ impl Project {
for (buffer, diff_base) in diff_bases_by_buffer {
let buffer_id = buffer.update(&mut cx, |buffer, cx| {
buffer.set_diff_base(diff_base.clone(), cx);
- buffer.remote_id()
+ buffer.remote_id().into()
})?;
if let Some(project_id) = remote_id {
client
@@ -7353,7 +7359,7 @@ impl Project {
) -> Result<proto::Ack> {
this.update(&mut cx, |this, cx| {
let payload = envelope.payload.clone();
- let buffer_id = payload.buffer_id;
+ let buffer_id = BufferId::new(payload.buffer_id)?;
let ops = payload
.operations
.into_iter()
@@ -7404,7 +7410,7 @@ impl Project {
as Arc<dyn language::File>);
}
- let buffer_id = state.id;
+ let buffer_id = BufferId::new(state.id)?;
let buffer = cx.new_model(|_| {
Buffer::from_proto(this.replica_id(), this.capability(), state, buffer_file)
.unwrap()
@@ -7413,9 +7419,10 @@ impl Project {
.insert(buffer_id, Some(buffer));
}
proto::create_buffer_for_peer::Variant::Chunk(chunk) => {
+ let buffer_id = BufferId::new(chunk.buffer_id)?;
let buffer = this
.incomplete_remote_buffers
- .get(&chunk.buffer_id)
+ .get(&buffer_id)
.cloned()
.flatten()
.ok_or_else(|| {
@@ -7432,7 +7439,7 @@ impl Project {
buffer.update(cx, |buffer, cx| buffer.apply_ops(operations, cx))?;
if chunk.is_last {
- this.incomplete_remote_buffers.remove(&chunk.buffer_id);
+ this.incomplete_remote_buffers.remove(&buffer_id);
this.register_buffer(&buffer, cx)?;
}
}
@@ -7450,6 +7457,7 @@ impl Project {
) -> Result<()> {
this.update(&mut cx, |this, cx| {
let buffer_id = envelope.payload.buffer_id;
+ let buffer_id = BufferId::new(buffer_id)?;
let diff_base = envelope.payload.diff_base;
if let Some(buffer) = this
.opened_buffers
@@ -7475,6 +7483,7 @@ impl Project {
mut cx: AsyncAppContext,
) -> Result<()> {
let buffer_id = envelope.payload.buffer_id;
+ let buffer_id = BufferId::new(buffer_id)?;
this.update(&mut cx, |this, cx| {
let payload = envelope.payload.clone();
@@ -7509,7 +7518,7 @@ impl Project {
_: Arc<Client>,
mut cx: AsyncAppContext,
) -> Result<proto::BufferSaved> {
- let buffer_id = envelope.payload.buffer_id;
+ let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
let (project_id, buffer) = this.update(&mut cx, |this, _cx| {
let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
let buffer = this
@@ -7530,7 +7539,7 @@ impl Project {
.await?;
Ok(buffer.update(&mut cx, |buffer, _| proto::BufferSaved {
project_id,
- buffer_id,
+ buffer_id: buffer_id.into(),
version: serialize_version(buffer.saved_version()),
mtime: Some(buffer.saved_mtime().into()),
fingerprint: language::proto::serialize_fingerprint(buffer.saved_version_fingerprint()),
@@ -7547,9 +7556,10 @@ impl Project {
let reload = this.update(&mut cx, |this, cx| {
let mut buffers = HashSet::default();
for buffer_id in &envelope.payload.buffer_ids {
+ let buffer_id = BufferId::new(*buffer_id)?;
buffers.insert(
this.opened_buffers
- .get(buffer_id)
+ .get(&buffer_id)
.and_then(|buffer| buffer.upgrade())
.ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
);
@@ -7580,12 +7590,12 @@ impl Project {
this.update(&mut cx, |this, cx| {
let Some(guest_id) = envelope.original_sender_id else {
error!("missing original_sender_id on SynchronizeBuffers request");
- return;
+ bail!("missing original_sender_id on SynchronizeBuffers request");
};
this.shared_buffers.entry(guest_id).or_default().clear();
for buffer in envelope.payload.buffers {
- let buffer_id = buffer.id;
+ let buffer_id = BufferId::new(buffer.id)?;
let remote_version = language::proto::deserialize_version(&buffer.version);
if let Some(buffer) = this.buffer_for_id(buffer_id) {
this.shared_buffers
@@ -7595,7 +7605,7 @@ impl Project {
let buffer = buffer.read(cx);
response.buffers.push(proto::BufferVersion {
- id: buffer_id,
+ id: buffer_id.into(),
version: language::proto::serialize_version(&buffer.version),
});
@@ -7605,7 +7615,7 @@ impl Project {
client
.send(proto::UpdateBufferFile {
project_id,
- buffer_id: buffer_id as u64,
+ buffer_id: buffer_id.into(),
file: Some(file.to_proto()),
})
.log_err();
@@ -7614,7 +7624,7 @@ impl Project {
client
.send(proto::UpdateDiffBase {
project_id,
- buffer_id: buffer_id as u64,
+ buffer_id: buffer_id.into(),
diff_base: buffer.diff_base().map(Into::into),
})
.log_err();
@@ -7622,7 +7632,7 @@ impl Project {
client
.send(proto::BufferReloaded {
project_id,
- buffer_id,
+ buffer_id: buffer_id.into(),
version: language::proto::serialize_version(buffer.saved_version()),
mtime: Some(buffer.saved_mtime().into()),
fingerprint: language::proto::serialize_fingerprint(
@@ -7642,7 +7652,7 @@ impl Project {
client
.request(proto::UpdateBuffer {
project_id,
- buffer_id,
+ buffer_id: buffer_id.into(),
operations: chunk,
})
.await?;
@@ -7654,7 +7664,8 @@ impl Project {
.detach();
}
}
- })?;
+ Ok(())
+ })??;
Ok(response)
}
@@ -7669,9 +7680,10 @@ impl Project {
let format = this.update(&mut cx, |this, cx| {
let mut buffers = HashSet::default();
for buffer_id in &envelope.payload.buffer_ids {
+ let buffer_id = BufferId::new(*buffer_id)?;
buffers.insert(
this.opened_buffers
- .get(buffer_id)
+ .get(&buffer_id)
.and_then(|buffer| buffer.upgrade())
.ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
);
@@ -7696,11 +7708,12 @@ impl Project {
mut cx: AsyncAppContext,
) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
let (buffer, completion) = this.update(&mut cx, |this, cx| {
+ let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
let buffer = this
.opened_buffers
- .get(&envelope.payload.buffer_id)
+ .get(&buffer_id)
.and_then(|buffer| buffer.upgrade())
- .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
+ .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
let language = buffer.read(cx).language();
let completion = language::proto::deserialize_completion(
envelope
@@ -7774,9 +7787,10 @@ impl Project {
.ok_or_else(|| anyhow!("invalid action"))?,
)?;
let apply_code_action = this.update(&mut cx, |this, cx| {
+ let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
let buffer = this
.opened_buffers
- .get(&envelope.payload.buffer_id)
+ .get(&buffer_id)
.and_then(|buffer| buffer.upgrade())
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx))
@@ -7798,11 +7812,12 @@ impl Project {
mut cx: AsyncAppContext,
) -> Result<proto::OnTypeFormattingResponse> {
let on_type_formatting = this.update(&mut cx, |this, cx| {
+ let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
let buffer = this
.opened_buffers
- .get(&envelope.payload.buffer_id)
+ .get(&buffer_id)
.and_then(|buffer| buffer.upgrade())
- .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
+ .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
let position = envelope
.payload
.position
@@ -7830,9 +7845,10 @@ impl Project {
mut cx: AsyncAppContext,
) -> Result<proto::InlayHintsResponse> {
let sender_id = envelope.original_sender_id()?;
+ let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
let buffer = this.update(&mut cx, |this, _| {
this.opened_buffers
- .get(&envelope.payload.buffer_id)
+ .get(&buffer_id)
.and_then(|buffer| buffer.upgrade())
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
})??;
@@ -7886,10 +7902,11 @@ impl Project {
let hint = InlayHints::proto_to_project_hint(proto_hint)
.context("resolved proto inlay hint conversion")?;
let buffer = this.update(&mut cx, |this, _cx| {
+ let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
this.opened_buffers
- .get(&envelope.payload.buffer_id)
+ .get(&buffer_id)
.and_then(|buffer| buffer.upgrade())
- .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
+ .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))
})??;
let response_hint = this
.update(&mut cx, |project, cx| {
@@ -7930,7 +7947,7 @@ impl Project {
<T::LspRequest as lsp::request::Request>::Result: Send,
{
let sender_id = envelope.original_sender_id()?;
- let buffer_id = T::buffer_id_from_proto(&envelope.payload);
+ let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
let buffer_handle = this.update(&mut cx, |this, _cx| {
this.opened_buffers
.get(&buffer_id)
@@ -7995,7 +8012,7 @@ impl Project {
let start = serialize_anchor(&range.start);
let end = serialize_anchor(&range.end);
let buffer_id = this.update(&mut cx, |this, cx| {
- this.create_buffer_for_peer(&buffer, peer_id, cx)
+ this.create_buffer_for_peer(&buffer, peer_id, cx).into()
})?;
locations.push(proto::Location {
buffer_id,
@@ -8037,7 +8054,7 @@ impl Project {
Ok(proto::OpenBufferForSymbolResponse {
buffer_id: this.update(&mut cx, |this, cx| {
- this.create_buffer_for_peer(&buffer, peer_id, cx)
+ this.create_buffer_for_peer(&buffer, peer_id, cx).into()
})?,
})
}
@@ -8057,14 +8074,13 @@ impl Project {
mut cx: AsyncAppContext,
) -> Result<proto::OpenBufferResponse> {
let peer_id = envelope.original_sender_id()?;
+ let buffer_id = BufferId::new(envelope.payload.id)?;
let buffer = this
- .update(&mut cx, |this, cx| {
- this.open_buffer_by_id(envelope.payload.id, cx)
- })?
+ .update(&mut cx, |this, cx| this.open_buffer_by_id(buffer_id, cx))?
.await?;
this.update(&mut cx, |this, cx| {
Ok(proto::OpenBufferResponse {
- buffer_id: this.create_buffer_for_peer(&buffer, peer_id, cx),
+ buffer_id: this.create_buffer_for_peer(&buffer, peer_id, cx).into(),
})
})?
}
@@ -8090,7 +8106,7 @@ impl Project {
let buffer = open_buffer.await?;
this.update(&mut cx, |this, cx| {
Ok(proto::OpenBufferResponse {
- buffer_id: this.create_buffer_for_peer(&buffer, peer_id, cx),
+ buffer_id: this.create_buffer_for_peer(&buffer, peer_id, cx).into(),
})
})?
}
@@ -8108,7 +8124,7 @@ impl Project {
for (buffer, transaction) in project_transaction.0 {
serialized_transaction
.buffer_ids
- .push(self.create_buffer_for_peer(&buffer, peer_id, cx));
+ .push(self.create_buffer_for_peer(&buffer, peer_id, cx).into());
serialized_transaction
.transactions
.push(language::proto::serialize_transaction(&transaction));
@@ -8126,6 +8142,7 @@ impl Project {
let mut project_transaction = ProjectTransaction::default();
for (buffer_id, transaction) in message.buffer_ids.into_iter().zip(message.transactions)
{
+ let buffer_id = BufferId::new(buffer_id)?;
let buffer = this
.update(&mut cx, |this, cx| {
this.wait_for_remote_buffer(buffer_id, cx)
@@ -8158,7 +8175,7 @@ impl Project {
buffer: &Model<Buffer>,
peer_id: proto::PeerId,
cx: &mut AppContext,
- ) -> u64 {
+ ) -> BufferId {
let buffer_id = buffer.read(cx).remote_id();
if let ProjectClientState::Shared { updates_tx, .. } = &self.client_state {
updates_tx
@@ -8170,7 +8187,7 @@ impl Project {
fn wait_for_remote_buffer(
&mut self,
- id: u64,
+ id: BufferId,
cx: &mut ModelContext<Self>,
) -> Task<Result<Model<Buffer>>> {
let mut opened_buffer_rx = self.opened_buffer.1.clone();
@@ -8239,7 +8256,7 @@ impl Project {
.filter_map(|(id, buffer)| {
let buffer = buffer.upgrade()?;
Some(proto::BufferVersion {
- id: *id,
+ id: (*id).into(),
version: language::proto::serialize_version(&buffer.read(cx).version),
})
})
@@ -8265,7 +8282,12 @@ impl Project {
.into_iter()
.map(|buffer| {
let client = client.clone();
- let buffer_id = buffer.id;
+ let buffer_id = match BufferId::new(buffer.id) {
+ Ok(id) => id,
+ Err(e) => {
+ return Task::ready(Err(e));
+ }
+ };
let remote_version = language::proto::deserialize_version(&buffer.version);
if let Some(buffer) = this.buffer_for_id(buffer_id) {
let operations =
@@ -8276,7 +8298,7 @@ impl Project {
client
.request(proto::UpdateBuffer {
project_id,
- buffer_id,
+ buffer_id: buffer_id.into(),
operations: chunk,
})
.await?;
@@ -8294,7 +8316,10 @@ impl Project {
// creates these buffers for us again to unblock any waiting futures.
for id in incomplete_buffer_ids {
cx.background_executor()
- .spawn(client.request(proto::OpenBufferById { project_id, id }))
+ .spawn(client.request(proto::OpenBufferById {
+ project_id,
+ id: id.into(),
+ }))
.detach();
}
@@ -8436,6 +8461,7 @@ impl Project {
) -> Result<()> {
let fingerprint = deserialize_fingerprint(&envelope.payload.fingerprint)?;
let version = deserialize_version(&envelope.payload.version);
+ let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
let mtime = envelope
.payload
.mtime
@@ -8445,11 +8471,11 @@ impl Project {
this.update(&mut cx, |this, cx| {
let buffer = this
.opened_buffers
- .get(&envelope.payload.buffer_id)
+ .get(&buffer_id)
.and_then(|buffer| buffer.upgrade())
.or_else(|| {
this.incomplete_remote_buffers
- .get(&envelope.payload.buffer_id)
+ .get(&buffer_id)
.and_then(|b| b.clone())
});
if let Some(buffer) = buffer {
@@ -8478,14 +8504,15 @@ impl Project {
.mtime
.ok_or_else(|| anyhow!("missing mtime"))?
.into();
+ let buffer_id = BufferId::new(payload.buffer_id)?;
this.update(&mut cx, |this, cx| {
let buffer = this
.opened_buffers
- .get(&payload.buffer_id)
+ .get(&buffer_id)
.and_then(|buffer| buffer.upgrade())
.or_else(|| {
this.incomplete_remote_buffers
- .get(&payload.buffer_id)
+ .get(&buffer_id)
.cloned()
.flatten()
});
@@ -62,6 +62,7 @@ use std::{
time::{Duration, SystemTime},
};
use sum_tree::{Bias, Edit, SeekTarget, SumTree, TreeMap, TreeSet};
+use text::BufferId;
use util::{
paths::{PathMatcher, HOME},
ResultExt,
@@ -672,7 +673,7 @@ impl LocalWorktree {
pub(crate) fn load_buffer(
&mut self,
- id: u64,
+ id: BufferId,
path: &Path,
cx: &mut ModelContext<Worktree>,
) -> Task<Result<Model<Buffer>>> {
@@ -1043,7 +1044,7 @@ impl LocalWorktree {
let buffer = buffer_handle.read(cx);
let rpc = self.client.clone();
- let buffer_id = buffer.remote_id();
+ let buffer_id: u64 = buffer.remote_id().into();
let project_id = self.share.as_ref().map(|share| share.project_id);
let text = buffer.as_rope().clone();
@@ -1481,7 +1482,7 @@ impl RemoteWorktree {
cx: &mut ModelContext<Worktree>,
) -> Task<Result<()>> {
let buffer = buffer_handle.read(cx);
- let buffer_id = buffer.remote_id();
+ let buffer_id = buffer.remote_id().into();
let version = buffer.version();
let rpc = self.client.clone();
let project_id = self.project_id;
@@ -2840,7 +2841,7 @@ impl language::LocalFile for File {
fn buffer_reloaded(
&self,
- buffer_id: u64,
+ buffer_id: BufferId,
version: &clock::Global,
fingerprint: RopeFingerprint,
line_ending: LineEnding,
@@ -2853,7 +2854,7 @@ impl language::LocalFile for File {
.client
.send(proto::BufferReloaded {
project_id,
- buffer_id,
+ buffer_id: buffer_id.into(),
version: serialize_version(version),
mtime: Some(mtime.into()),
fingerprint: serialize_fingerprint(fingerprint),
@@ -21,6 +21,7 @@ use std::{
path::{Path, PathBuf},
sync::Arc,
};
+use text::BufferId;
use util::{http::FakeHttpClient, test::temp_tree, ResultExt};
#[gpui::test]
@@ -511,9 +512,11 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
let prev_read_dir_count = fs.read_dir_call_count();
let buffer = tree
.update(cx, |tree, cx| {
- tree.as_local_mut()
- .unwrap()
- .load_buffer(0, "one/node_modules/b/b1.js".as_ref(), cx)
+ tree.as_local_mut().unwrap().load_buffer(
+ BufferId::new(1).unwrap(),
+ "one/node_modules/b/b1.js".as_ref(),
+ cx,
+ )
})
.await
.unwrap();
@@ -553,9 +556,11 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
let prev_read_dir_count = fs.read_dir_call_count();
let buffer = tree
.update(cx, |tree, cx| {
- tree.as_local_mut()
- .unwrap()
- .load_buffer(0, "one/node_modules/a/a2.js".as_ref(), cx)
+ tree.as_local_mut().unwrap().load_buffer(
+ BufferId::new(1).unwrap(),
+ "one/node_modules/a/a2.js".as_ref(),
+ cx,
+ )
})
.await
.unwrap();
@@ -1007,7 +1007,7 @@ mod tests {
use super::*;
use editor::{DisplayPoint, Editor};
use gpui::{Context, Hsla, TestAppContext, VisualTestContext};
- use language::Buffer;
+ use language::{Buffer, BufferId};
use smol::stream::StreamExt as _;
use unindent::Unindent as _;
@@ -1029,7 +1029,7 @@ mod tests {
let buffer = cx.new_model(|cx| {
Buffer::new(
0,
- cx.entity_id().as_u64(),
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
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
@@ -1385,7 +1385,13 @@ mod tests {
expected_query_matches_count > 1,
"Should pick a query with multiple results"
);
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), buffer_text));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ buffer_text,
+ )
+ });
let window = cx.add_window(|_| ());
let editor = window.build_view(cx, |cx| Editor::for_buffer(buffer.clone(), None, cx));
@@ -1581,7 +1587,13 @@ mod tests {
for "find" or "find and replace" operations on strings, or for input validation.
"#
.unindent();
- let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), buffer_text));
+ let buffer = cx.new_model(|cx| {
+ Buffer::new(
+ 0,
+ BufferId::new(cx.entity_id().as_u64()).unwrap(),
+ buffer_text,
+ )
+ });
let cx = cx.add_empty_window();
let editor = cx.new_view(|cx| Editor::for_buffer(buffer.clone(), None, cx));
@@ -1,6 +1,6 @@
use crate::{
- locator::Locator, BufferSnapshot, Point, PointUtf16, TextDimension, ToOffset, ToPoint,
- ToPointUtf16,
+ locator::Locator, BufferId, BufferSnapshot, Point, PointUtf16, TextDimension, ToOffset,
+ ToPoint, ToPointUtf16,
};
use anyhow::Result;
use std::{cmp::Ordering, fmt::Debug, ops::Range};
@@ -11,7 +11,7 @@ pub struct Anchor {
pub timestamp: clock::Lamport,
pub offset: usize,
pub bias: Bias,
- pub buffer_id: Option<u64>,
+ pub buffer_id: Option<BufferId>,
}
impl Anchor {
@@ -18,7 +18,7 @@ fn init_logger() {
#[test]
fn test_edit() {
- let mut buffer = Buffer::new(0, 0, "abc".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "abc".into());
assert_eq!(buffer.text(), "abc");
buffer.edit([(3..3, "def")]);
assert_eq!(buffer.text(), "abcdef");
@@ -42,7 +42,7 @@ fn test_random_edits(mut rng: StdRng) {
let mut reference_string = RandomCharIter::new(&mut rng)
.take(reference_string_len)
.collect::<String>();
- let mut buffer = Buffer::new(0, 0, reference_string.clone());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), reference_string.clone());
LineEnding::normalize(&mut reference_string);
buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
@@ -164,7 +164,7 @@ fn test_line_endings() {
LineEnding::Windows
);
- let mut buffer = Buffer::new(0, 0, "one\r\ntwo\rthree".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "one\r\ntwo\rthree".into());
assert_eq!(buffer.text(), "one\ntwo\nthree");
assert_eq!(buffer.line_ending(), LineEnding::Windows);
buffer.check_invariants();
@@ -178,7 +178,7 @@ fn test_line_endings() {
#[test]
fn test_line_len() {
- let mut buffer = Buffer::new(0, 0, "".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "".into());
buffer.edit([(0..0, "abcd\nefg\nhij")]);
buffer.edit([(12..12, "kl\nmno")]);
buffer.edit([(18..18, "\npqrs\n")]);
@@ -195,7 +195,7 @@ fn test_line_len() {
#[test]
fn test_common_prefix_at_position() {
let text = "a = str; b = δα";
- let buffer = Buffer::new(0, 0, text.into());
+ let buffer = Buffer::new(0, BufferId::new(1).unwrap(), text.into());
let offset1 = offset_after(text, "str");
let offset2 = offset_after(text, "δα");
@@ -243,7 +243,11 @@ fn test_common_prefix_at_position() {
#[test]
fn test_text_summary_for_range() {
- let buffer = Buffer::new(0, 0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz".into());
+ let buffer = Buffer::new(
+ 0,
+ BufferId::new(1).unwrap(),
+ "ab\nefg\nhklm\nnopqrs\ntuvwxyz".into(),
+ );
assert_eq!(
buffer.text_summary_for_range::<TextSummary, _>(1..3),
TextSummary {
@@ -313,7 +317,7 @@ fn test_text_summary_for_range() {
#[test]
fn test_chars_at() {
- let mut buffer = Buffer::new(0, 0, "".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "".into());
buffer.edit([(0..0, "abcd\nefgh\nij")]);
buffer.edit([(12..12, "kl\nmno")]);
buffer.edit([(18..18, "\npqrs")]);
@@ -335,7 +339,7 @@ fn test_chars_at() {
assert_eq!(chars.collect::<String>(), "PQrs");
// Regression test:
- let mut buffer = Buffer::new(0, 0, "".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "".into());
buffer.edit([(0..0, "[workspace]\nmembers = [\n \"xray_core\",\n \"xray_server\",\n \"xray_cli\",\n \"xray_wasm\",\n]\n")]);
buffer.edit([(60..60, "\n")]);
@@ -345,7 +349,7 @@ fn test_chars_at() {
#[test]
fn test_anchors() {
- let mut buffer = Buffer::new(0, 0, "".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "".into());
buffer.edit([(0..0, "abc")]);
let left_anchor = buffer.anchor_before(2);
let right_anchor = buffer.anchor_after(2);
@@ -463,7 +467,7 @@ fn test_anchors() {
#[test]
fn test_anchors_at_start_and_end() {
- let mut buffer = Buffer::new(0, 0, "".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "".into());
let before_start_anchor = buffer.anchor_before(0);
let after_end_anchor = buffer.anchor_after(0);
@@ -486,7 +490,7 @@ fn test_anchors_at_start_and_end() {
#[test]
fn test_undo_redo() {
- let mut buffer = Buffer::new(0, 0, "1234".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "1234".into());
// Set group interval to zero so as to not group edits in the undo stack.
buffer.set_group_interval(Duration::from_secs(0));
@@ -523,7 +527,7 @@ fn test_undo_redo() {
#[test]
fn test_history() {
let mut now = Instant::now();
- let mut buffer = Buffer::new(0, 0, "123456".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "123456".into());
buffer.set_group_interval(Duration::from_millis(300));
let transaction_1 = buffer.start_transaction_at(now).unwrap();
@@ -590,7 +594,7 @@ fn test_history() {
#[test]
fn test_finalize_last_transaction() {
let now = Instant::now();
- let mut buffer = Buffer::new(0, 0, "123456".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "123456".into());
buffer.start_transaction_at(now);
buffer.edit([(2..4, "cd")]);
@@ -625,7 +629,7 @@ fn test_finalize_last_transaction() {
#[test]
fn test_edited_ranges_for_transaction() {
let now = Instant::now();
- let mut buffer = Buffer::new(0, 0, "1234567".into());
+ let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "1234567".into());
buffer.start_transaction_at(now);
buffer.edit([(2..4, "cd")]);
@@ -664,9 +668,9 @@ fn test_edited_ranges_for_transaction() {
fn test_concurrent_edits() {
let text = "abcdef";
- let mut buffer1 = Buffer::new(1, 0, text.into());
- let mut buffer2 = Buffer::new(2, 0, text.into());
- let mut buffer3 = Buffer::new(3, 0, text.into());
+ let mut buffer1 = Buffer::new(1, BufferId::new(1).unwrap(), text.into());
+ let mut buffer2 = Buffer::new(2, BufferId::new(1).unwrap(), text.into());
+ let mut buffer3 = Buffer::new(3, BufferId::new(1).unwrap(), text.into());
let buf1_op = buffer1.edit([(1..2, "12")]);
assert_eq!(buffer1.text(), "a12cdef");
@@ -705,7 +709,7 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
let mut network = Network::new(rng.clone());
for i in 0..peers {
- let mut buffer = Buffer::new(i as ReplicaId, 0, base_text.clone());
+ let mut buffer = Buffer::new(i as ReplicaId, BufferId::new(1).unwrap(), base_text.clone());
buffer.history.group_interval = Duration::from_millis(rng.gen_range(0..=200));
buffers.push(buffer);
replica_ids.push(i as u16);
@@ -26,6 +26,7 @@ pub use selection::*;
use std::{
borrow::Cow,
cmp::{self, Ordering, Reverse},
+ fmt::Display,
future::Future,
iter::Iterator,
ops::{self, Deref, Range, Sub},
@@ -59,10 +60,39 @@ pub struct Buffer {
wait_for_version_txs: Vec<(clock::Global, oneshot::Sender<()>)>,
}
+#[repr(transparent)]
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, PartialOrd, Ord, Eq)]
+pub struct BufferId(u64);
+
+impl Display for BufferId {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+
+impl BufferId {
+ /// Returns Err if `id` is outside of BufferId domain.
+ pub fn new(id: u64) -> anyhow::Result<Self> {
+ Ok(Self(id))
+ }
+ /// Increments this buffer id, returning the old value.
+ /// So that's a post-increment operator in disguise.
+ pub fn next(&mut self) -> Self {
+ let old = *self;
+ self.0 += 1;
+ old
+ }
+}
+impl From<BufferId> for u64 {
+ fn from(id: BufferId) -> Self {
+ id.0
+ }
+}
+
#[derive(Clone)]
pub struct BufferSnapshot {
replica_id: ReplicaId,
- remote_id: u64,
+ remote_id: BufferId,
visible_text: Rope,
deleted_text: Rope,
line_ending: LineEnding,
@@ -369,7 +399,7 @@ struct Edits<'a, D: TextDimension, F: FnMut(&FragmentSummary) -> bool> {
old_end: D,
new_end: D,
range: Range<(&'a Locator, usize)>,
- buffer_id: u64,
+ buffer_id: BufferId,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
@@ -478,7 +508,7 @@ pub struct UndoOperation {
}
impl Buffer {
- pub fn new(replica_id: u16, remote_id: u64, mut base_text: String) -> Buffer {
+ pub fn new(replica_id: u16, remote_id: BufferId, mut base_text: String) -> Buffer {
let line_ending = LineEnding::detect(&base_text);
LineEnding::normalize(&mut base_text);
@@ -545,7 +575,7 @@ impl Buffer {
self.lamport_clock.replica_id
}
- pub fn remote_id(&self) -> u64 {
+ pub fn remote_id(&self) -> BufferId {
self.remote_id
}
@@ -1590,7 +1620,7 @@ impl BufferSnapshot {
&self.visible_text
}
- pub fn remote_id(&self) -> u64 {
+ pub fn remote_id(&self) -> BufferId {
self.remote_id
}
@@ -69,14 +69,14 @@ mod test {
use crate::{test::VimTestContext, Vim};
use editor::Editor;
use gpui::{Context, Entity, VisualTestContext};
- use language::Buffer;
+ use language::{Buffer, BufferId};
// regression test for blur called with a different active editor
#[gpui::test]
async fn test_blur_focus(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
- let buffer = cx.new_model(|_| Buffer::new(0, 0, "a = 1\nb = 2\n"));
+ let buffer = cx.new_model(|_| Buffer::new(0, BufferId::new(1).unwrap(), "a = 1\nb = 2\n"));
let window2 = cx.add_window(|cx| Editor::for_buffer(buffer, None, cx));
let editor2 = cx
.update(|cx| {
@@ -111,7 +111,7 @@ mod test {
let mut cx1 = VisualTestContext::from_window(cx.window, &cx);
let editor1 = cx.editor.clone();
- let buffer = cx.new_model(|_| Buffer::new(0, 0, "a = 1\nb = 2\n"));
+ let buffer = cx.new_model(|_| Buffer::new(0, BufferId::new(1).unwrap(), "a = 1\nb = 2\n"));
let (editor2, cx2) = cx.add_window_view(|cx| Editor::for_buffer(buffer, None, cx));
editor2.update(cx2, |_, cx| {
@@ -278,6 +278,7 @@ mod tests {
use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer};
use settings::SettingsStore;
use std::num::NonZeroU32;
+ use text::BufferId;
#[gpui::test]
async fn test_c_autoindent(cx: &mut TestAppContext) {
@@ -295,8 +296,8 @@ mod tests {
let language = crate::languages::language("c", tree_sitter_c::language(), None).await;
cx.new_model(|cx| {
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), "").with_language(language, cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "")
+ .with_language(language, cx);
// empty function
buffer.edit([(0..0, "int main() {}")], None, cx);
@@ -181,6 +181,7 @@ mod tests {
use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer};
use settings::SettingsStore;
use std::num::NonZeroU32;
+ use text::BufferId;
#[gpui::test]
async fn test_python_autoindent(cx: &mut TestAppContext) {
@@ -199,8 +200,8 @@ mod tests {
});
cx.new_model(|cx| {
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), "").with_language(language, cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "")
+ .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);
@@ -297,6 +297,7 @@ mod tests {
use gpui::{Context, Hsla, TestAppContext};
use language::language_settings::AllLanguageSettings;
use settings::SettingsStore;
+ use text::BufferId;
use theme::SyntaxTheme;
#[gpui::test]
@@ -509,8 +510,8 @@ mod tests {
let language = crate::languages::language("rust", tree_sitter_rust::language(), None).await;
cx.new_model(|cx| {
- let mut buffer =
- Buffer::new(0, cx.entity_id().as_u64(), "").with_language(language, cx);
+ let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "")
+ .with_language(language, cx);
// indent between braces
buffer.set_text("fn a() {}", cx);
@@ -349,6 +349,7 @@ async fn get_cached_eslint_server_binary(
#[cfg(test)]
mod tests {
use gpui::{Context, TestAppContext};
+ use text::BufferId;
use unindent::Unindent;
#[gpui::test]
@@ -376,7 +377,8 @@ mod tests {
.unindent();
let buffer = cx.new_model(|cx| {
- language::Buffer::new(0, cx.entity_id().as_u64(), text).with_language(language, cx)
+ language::Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
+ .with_language(language, cx)
});
let outline = buffer.update(cx, |buffer, _| buffer.snapshot().outline(None).unwrap());
assert_eq!(