mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-03 08:54:04 +00:00
Fix race condition when opening a buffer and getting a definition to it
This commit is contained in:
parent
93125cbd16
commit
96b66dcce1
7 changed files with 160 additions and 135 deletions
|
@ -305,7 +305,7 @@ impl Buffer {
|
||||||
|
|
||||||
pub fn from_proto(
|
pub fn from_proto(
|
||||||
replica_id: ReplicaId,
|
replica_id: ReplicaId,
|
||||||
message: proto::Buffer,
|
message: proto::BufferState,
|
||||||
file: Option<Box<dyn File>>,
|
file: Option<Box<dyn File>>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
|
@ -359,8 +359,8 @@ impl Buffer {
|
||||||
Ok(this)
|
Ok(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_proto(&self) -> proto::Buffer {
|
pub fn to_proto(&self) -> proto::BufferState {
|
||||||
proto::Buffer {
|
proto::BufferState {
|
||||||
id: self.remote_id(),
|
id: self.remote_id(),
|
||||||
file: self.file.as_ref().map(|f| f.to_proto()),
|
file: self.file.as_ref().map(|f| f.to_proto()),
|
||||||
visible_text: self.text.text(),
|
visible_text: self.text.text(),
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rpc::proto;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use text::*;
|
use text::*;
|
||||||
|
|
||||||
pub use proto::{Buffer, SelectionSet};
|
pub use proto::{Buffer, BufferState, SelectionSet};
|
||||||
|
|
||||||
pub fn serialize_operation(operation: &Operation) -> proto::Operation {
|
pub fn serialize_operation(operation: &Operation) -> proto::Operation {
|
||||||
proto::Operation {
|
proto::Operation {
|
||||||
|
|
|
@ -518,17 +518,18 @@ impl Project {
|
||||||
let (mut tx, rx) = postage::watch::channel();
|
let (mut tx, rx) = postage::watch::channel();
|
||||||
entry.insert(rx.clone());
|
entry.insert(rx.clone());
|
||||||
|
|
||||||
let load_buffer = worktree.update(cx, |worktree, cx| {
|
let load_buffer = if worktree.read(cx).is_local() {
|
||||||
worktree.load_buffer(&project_path.path, cx)
|
self.open_local_buffer(&project_path.path, &worktree, cx)
|
||||||
});
|
} else {
|
||||||
|
self.open_remote_buffer(&project_path.path, &worktree, cx)
|
||||||
|
};
|
||||||
|
|
||||||
cx.spawn(move |this, mut cx| async move {
|
cx.spawn(move |this, mut cx| async move {
|
||||||
let load_result = load_buffer.await;
|
let load_result = load_buffer.await;
|
||||||
*tx.borrow_mut() = Some(this.update(&mut cx, |this, cx| {
|
*tx.borrow_mut() = Some(this.update(&mut cx, |this, _| {
|
||||||
// Record the fact that the buffer is no longer loading.
|
// Record the fact that the buffer is no longer loading.
|
||||||
this.loading_buffers.remove(&project_path);
|
this.loading_buffers.remove(&project_path);
|
||||||
let buffer = load_result.map_err(Arc::new)?;
|
let buffer = load_result.map_err(Arc::new)?;
|
||||||
this.register_buffer(&buffer, &worktree, cx)?;
|
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
|
@ -550,6 +551,55 @@ impl Project {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn open_local_buffer(
|
||||||
|
&mut self,
|
||||||
|
path: &Arc<Path>,
|
||||||
|
worktree: &ModelHandle<Worktree>,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) -> Task<Result<ModelHandle<Buffer>>> {
|
||||||
|
let load_buffer = worktree.update(cx, |worktree, cx| {
|
||||||
|
let worktree = worktree.as_local_mut().unwrap();
|
||||||
|
worktree.load_buffer(path, cx)
|
||||||
|
});
|
||||||
|
let worktree = worktree.downgrade();
|
||||||
|
cx.spawn(|this, mut cx| async move {
|
||||||
|
let buffer = load_buffer.await?;
|
||||||
|
let worktree = worktree
|
||||||
|
.upgrade(&cx)
|
||||||
|
.ok_or_else(|| anyhow!("worktree was removed"))?;
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
this.register_buffer(&buffer, Some(&worktree), cx)
|
||||||
|
})?;
|
||||||
|
Ok(buffer)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_remote_buffer(
|
||||||
|
&mut self,
|
||||||
|
path: &Arc<Path>,
|
||||||
|
worktree: &ModelHandle<Worktree>,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) -> Task<Result<ModelHandle<Buffer>>> {
|
||||||
|
let rpc = self.client.clone();
|
||||||
|
let project_id = self.remote_id().unwrap();
|
||||||
|
let remote_worktree_id = worktree.read(cx).id();
|
||||||
|
let path = path.clone();
|
||||||
|
let path_string = path.to_string_lossy().to_string();
|
||||||
|
cx.spawn(|this, mut cx| async move {
|
||||||
|
let response = rpc
|
||||||
|
.request(proto::OpenBuffer {
|
||||||
|
project_id,
|
||||||
|
worktree_id: remote_worktree_id.to_proto(),
|
||||||
|
path: path_string,
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
let buffer = response.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
this.deserialize_remote_buffer(buffer, cx)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn save_buffer_as(
|
pub fn save_buffer_as(
|
||||||
&self,
|
&self,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
@ -568,7 +618,7 @@ impl Project {
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.assign_language_to_buffer(&buffer, &worktree, cx);
|
this.assign_language_to_buffer(&buffer, Some(&worktree), cx);
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -619,7 +669,7 @@ impl Project {
|
||||||
fn register_buffer(
|
fn register_buffer(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &ModelHandle<Buffer>,
|
buffer: &ModelHandle<Buffer>,
|
||||||
worktree: &ModelHandle<Worktree>,
|
worktree: Option<&ModelHandle<Worktree>>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match self.open_buffers.insert(
|
match self.open_buffers.insert(
|
||||||
|
@ -627,21 +677,21 @@ impl Project {
|
||||||
OpenBuffer::Loaded(buffer.downgrade()),
|
OpenBuffer::Loaded(buffer.downgrade()),
|
||||||
) {
|
) {
|
||||||
Some(OpenBuffer::Operations(pending_ops)) => {
|
Some(OpenBuffer::Operations(pending_ops)) => {
|
||||||
buffer.update(cx, |buf, cx| buf.apply_ops(pending_ops, cx))?;
|
// buffer.update(cx, |buf, cx| buf.apply_ops(pending_ops, cx))?;
|
||||||
}
|
}
|
||||||
Some(OpenBuffer::Loaded(_)) => {
|
Some(OpenBuffer::Loaded(_)) => {
|
||||||
return Err(anyhow!("registered the same buffer twice"));
|
return Err(anyhow!("registered the same buffer twice"));
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
self.assign_language_to_buffer(&buffer, &worktree, cx);
|
self.assign_language_to_buffer(&buffer, worktree, cx);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_language_to_buffer(
|
fn assign_language_to_buffer(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &ModelHandle<Buffer>,
|
buffer: &ModelHandle<Buffer>,
|
||||||
worktree: &ModelHandle<Worktree>,
|
worktree: Option<&ModelHandle<Worktree>>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let (path, full_path) = {
|
let (path, full_path) = {
|
||||||
|
@ -657,7 +707,7 @@ impl Project {
|
||||||
|
|
||||||
// For local worktrees, start a language server if needed.
|
// For local worktrees, start a language server if needed.
|
||||||
// Also assign the language server and any previously stored diagnostics to the buffer.
|
// Also assign the language server and any previously stored diagnostics to the buffer.
|
||||||
if let Some(local_worktree) = worktree.read(cx).as_local() {
|
if let Some(local_worktree) = worktree.and_then(|w| w.read(cx).as_local()) {
|
||||||
let worktree_id = local_worktree.id();
|
let worktree_id = local_worktree.id();
|
||||||
let worktree_abs_path = local_worktree.abs_path().clone();
|
let worktree_abs_path = local_worktree.abs_path().clone();
|
||||||
|
|
||||||
|
@ -681,7 +731,7 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(local_worktree) = worktree.read(cx).as_local() {
|
if let Some(local_worktree) = worktree.and_then(|w| w.read(cx).as_local()) {
|
||||||
if let Some(diagnostics) = local_worktree.diagnostics_for_path(&path) {
|
if let Some(diagnostics) = local_worktree.diagnostics_for_path(&path) {
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.update_diagnostics(None, diagnostics, cx).log_err();
|
buffer.update_diagnostics(None, diagnostics, cx).log_err();
|
||||||
|
@ -1067,7 +1117,6 @@ impl Project {
|
||||||
})
|
})
|
||||||
} else if let Some(project_id) = self.remote_id() {
|
} else if let Some(project_id) = self.remote_id() {
|
||||||
let client = self.client.clone();
|
let client = self.client.clone();
|
||||||
let replica_id = self.replica_id();
|
|
||||||
let request = proto::GetDefinition {
|
let request = proto::GetDefinition {
|
||||||
project_id,
|
project_id,
|
||||||
buffer_id: source_buffer.remote_id(),
|
buffer_id: source_buffer.remote_id(),
|
||||||
|
@ -1078,35 +1127,10 @@ impl Project {
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
let mut definitions = Vec::new();
|
let mut definitions = Vec::new();
|
||||||
for definition in response.definitions {
|
for definition in response.definitions {
|
||||||
let target_buffer = match definition
|
let target_buffer = this.deserialize_remote_buffer(
|
||||||
.buffer
|
definition.buffer.ok_or_else(|| anyhow!("missing buffer"))?,
|
||||||
.ok_or_else(|| anyhow!("missing buffer"))?
|
cx,
|
||||||
{
|
)?;
|
||||||
proto::definition::Buffer::Id(id) => this
|
|
||||||
.open_buffers
|
|
||||||
.get(&(id as usize))
|
|
||||||
.and_then(|buffer| buffer.upgrade(cx))
|
|
||||||
.ok_or_else(|| anyhow!("no buffer exists for id {}", id))?,
|
|
||||||
proto::definition::Buffer::State(mut buffer) => {
|
|
||||||
let file = if let Some(file) = buffer.file.take() {
|
|
||||||
let worktree_id = WorktreeId::from_proto(file.worktree_id);
|
|
||||||
let worktree =
|
|
||||||
this.worktree_for_id(worktree_id, cx).ok_or_else(|| {
|
|
||||||
anyhow!("no worktree found for id {}", file.worktree_id)
|
|
||||||
})?;
|
|
||||||
let file = File::from_proto(file, worktree.clone(), cx)?;
|
|
||||||
Some(Box::new(file) as Box<dyn language::File>)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let buffer = cx.add_model(|cx| {
|
|
||||||
Buffer::from_proto(replica_id, buffer, file, cx).unwrap()
|
|
||||||
});
|
|
||||||
this.register_buffer(&buffer, &worktree, cx)?;
|
|
||||||
buffer
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let target_start = definition
|
let target_start = definition
|
||||||
.target_start
|
.target_start
|
||||||
.and_then(deserialize_anchor)
|
.and_then(deserialize_anchor)
|
||||||
|
@ -1712,17 +1736,8 @@ impl Project {
|
||||||
};
|
};
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
for definition in definitions {
|
for definition in definitions {
|
||||||
let buffer_id = definition.target_buffer.read(cx).remote_id();
|
let buffer =
|
||||||
let shared_buffers = this.shared_buffers.entry(sender_id).or_default();
|
this.serialize_buffer_for_peer(&definition.target_buffer, sender_id, cx);
|
||||||
let buffer = match shared_buffers.entry(buffer_id) {
|
|
||||||
hash_map::Entry::Occupied(_) => proto::definition::Buffer::Id(buffer_id),
|
|
||||||
hash_map::Entry::Vacant(entry) => {
|
|
||||||
entry.insert(definition.target_buffer.clone());
|
|
||||||
proto::definition::Buffer::State(
|
|
||||||
definition.target_buffer.read(cx).to_proto(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
response.definitions.push(proto::Definition {
|
response.definitions.push(proto::Definition {
|
||||||
target_start: Some(serialize_anchor(&definition.target_range.start)),
|
target_start: Some(serialize_anchor(&definition.target_range.start)),
|
||||||
target_end: Some(serialize_anchor(&definition.target_range.end)),
|
target_end: Some(serialize_anchor(&definition.target_range.end)),
|
||||||
|
@ -1757,17 +1772,13 @@ impl Project {
|
||||||
cx.spawn(|this, mut cx| {
|
cx.spawn(|this, mut cx| {
|
||||||
async move {
|
async move {
|
||||||
let buffer = open_buffer.await?;
|
let buffer = open_buffer.await?;
|
||||||
this.update(&mut cx, |this, _| {
|
let buffer = this.update(&mut cx, |this, cx| {
|
||||||
this.shared_buffers
|
this.serialize_buffer_for_peer(&buffer, peer_id, cx)
|
||||||
.entry(peer_id)
|
|
||||||
.or_default()
|
|
||||||
.insert(buffer.id() as u64, buffer.clone());
|
|
||||||
});
|
});
|
||||||
let message = buffer.read_with(&cx, |buffer, _| buffer.to_proto());
|
|
||||||
rpc.respond(
|
rpc.respond(
|
||||||
receipt,
|
receipt,
|
||||||
proto::OpenBufferResponse {
|
proto::OpenBufferResponse {
|
||||||
buffer: Some(message),
|
buffer: Some(buffer),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -1778,6 +1789,60 @@ impl Project {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_buffer_for_peer(
|
||||||
|
&mut self,
|
||||||
|
buffer: &ModelHandle<Buffer>,
|
||||||
|
peer_id: PeerId,
|
||||||
|
cx: &AppContext,
|
||||||
|
) -> proto::Buffer {
|
||||||
|
let buffer_id = buffer.read(cx).remote_id();
|
||||||
|
let shared_buffers = self.shared_buffers.entry(peer_id).or_default();
|
||||||
|
match shared_buffers.entry(buffer_id) {
|
||||||
|
hash_map::Entry::Occupied(_) => proto::Buffer {
|
||||||
|
variant: Some(proto::buffer::Variant::Id(buffer_id)),
|
||||||
|
},
|
||||||
|
hash_map::Entry::Vacant(entry) => {
|
||||||
|
entry.insert(buffer.clone());
|
||||||
|
proto::Buffer {
|
||||||
|
variant: Some(proto::buffer::Variant::State(buffer.read(cx).to_proto())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_remote_buffer(
|
||||||
|
&mut self,
|
||||||
|
buffer: proto::Buffer,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) -> Result<ModelHandle<Buffer>> {
|
||||||
|
match buffer.variant.ok_or_else(|| anyhow!("missing buffer"))? {
|
||||||
|
proto::buffer::Variant::Id(id) => self
|
||||||
|
.open_buffers
|
||||||
|
.get(&(id as usize))
|
||||||
|
.and_then(|buffer| buffer.upgrade(cx))
|
||||||
|
.ok_or_else(|| anyhow!("no buffer exists for id {}", id)),
|
||||||
|
proto::buffer::Variant::State(mut buffer) => {
|
||||||
|
let mut buffer_worktree = None;
|
||||||
|
let mut buffer_file = None;
|
||||||
|
if let Some(file) = buffer.file.take() {
|
||||||
|
let worktree_id = WorktreeId::from_proto(file.worktree_id);
|
||||||
|
let worktree = self
|
||||||
|
.worktree_for_id(worktree_id, cx)
|
||||||
|
.ok_or_else(|| anyhow!("no worktree found for id {}", file.worktree_id))?;
|
||||||
|
buffer_file = Some(Box::new(File::from_proto(file, worktree.clone(), cx)?)
|
||||||
|
as Box<dyn language::File>);
|
||||||
|
buffer_worktree = Some(worktree);
|
||||||
|
}
|
||||||
|
|
||||||
|
let buffer = cx.add_model(|cx| {
|
||||||
|
Buffer::from_proto(self.replica_id(), buffer, buffer_file, cx).unwrap()
|
||||||
|
});
|
||||||
|
self.register_buffer(&buffer, buffer_worktree.as_ref(), cx)?;
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_close_buffer(
|
pub fn handle_close_buffer(
|
||||||
&mut self,
|
&mut self,
|
||||||
envelope: TypedEnvelope<proto::CloseBuffer>,
|
envelope: TypedEnvelope<proto::CloseBuffer>,
|
||||||
|
|
|
@ -367,17 +367,6 @@ impl Worktree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_buffer(
|
|
||||||
&mut self,
|
|
||||||
path: &Path,
|
|
||||||
cx: &mut ModelContext<Self>,
|
|
||||||
) -> Task<Result<ModelHandle<Buffer>>> {
|
|
||||||
match self {
|
|
||||||
Worktree::Local(worktree) => worktree.load_buffer(path, cx),
|
|
||||||
Worktree::Remote(worktree) => worktree.load_buffer(path, cx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn diagnostic_summaries<'a>(
|
pub fn diagnostic_summaries<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
) -> impl Iterator<Item = (Arc<Path>, DiagnosticSummary)> + 'a {
|
) -> impl Iterator<Item = (Arc<Path>, DiagnosticSummary)> + 'a {
|
||||||
|
@ -834,41 +823,6 @@ impl LocalWorktree {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RemoteWorktree {
|
impl RemoteWorktree {
|
||||||
pub(crate) fn load_buffer(
|
|
||||||
&mut self,
|
|
||||||
path: &Path,
|
|
||||||
cx: &mut ModelContext<Worktree>,
|
|
||||||
) -> Task<Result<ModelHandle<Buffer>>> {
|
|
||||||
let rpc = self.client.clone();
|
|
||||||
let replica_id = self.replica_id;
|
|
||||||
let project_id = self.project_id;
|
|
||||||
let remote_worktree_id = self.id();
|
|
||||||
let path: Arc<Path> = Arc::from(path);
|
|
||||||
let path_string = path.to_string_lossy().to_string();
|
|
||||||
cx.spawn_weak(move |this, mut cx| async move {
|
|
||||||
let response = rpc
|
|
||||||
.request(proto::OpenBuffer {
|
|
||||||
project_id,
|
|
||||||
worktree_id: remote_worktree_id.to_proto(),
|
|
||||||
path: path_string,
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let this = this
|
|
||||||
.upgrade(&cx)
|
|
||||||
.ok_or_else(|| anyhow!("worktree was closed"))?;
|
|
||||||
let mut remote_buffer = response.buffer.ok_or_else(|| anyhow!("empty buffer"))?;
|
|
||||||
let file = remote_buffer
|
|
||||||
.file
|
|
||||||
.take()
|
|
||||||
.map(|proto| cx.read(|cx| File::from_proto(proto, this.clone(), cx)))
|
|
||||||
.transpose()?
|
|
||||||
.map(|file| Box::new(file) as Box<dyn language::File>);
|
|
||||||
|
|
||||||
Ok(cx.add_model(|cx| Buffer::from_proto(replica_id, remote_buffer, file, cx).unwrap()))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn snapshot(&self) -> Snapshot {
|
fn snapshot(&self) -> Snapshot {
|
||||||
self.snapshot.clone()
|
self.snapshot.clone()
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,12 +147,9 @@ message GetDefinitionResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
message Definition {
|
message Definition {
|
||||||
oneof buffer {
|
Buffer buffer = 1;
|
||||||
uint64 id = 1;
|
Anchor target_start = 2;
|
||||||
Buffer state = 2;
|
Anchor target_end = 3;
|
||||||
}
|
|
||||||
Anchor target_start = 3;
|
|
||||||
Anchor target_end = 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message OpenBuffer {
|
message OpenBuffer {
|
||||||
|
@ -324,6 +321,13 @@ message Entry {
|
||||||
}
|
}
|
||||||
|
|
||||||
message Buffer {
|
message Buffer {
|
||||||
|
oneof variant {
|
||||||
|
uint64 id = 1;
|
||||||
|
BufferState state = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message BufferState {
|
||||||
uint64 id = 1;
|
uint64 id = 1;
|
||||||
optional File file = 2;
|
optional File file = 2;
|
||||||
string visible_text = 3;
|
string visible_text = 3;
|
||||||
|
|
|
@ -410,9 +410,7 @@ mod tests {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
proto::OpenBufferResponse {
|
proto::OpenBufferResponse {
|
||||||
buffer: Some(proto::Buffer {
|
buffer: Some(proto::Buffer {
|
||||||
id: 101,
|
variant: Some(proto::buffer::Variant::Id(0))
|
||||||
visible_text: "path/one content".to_string(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -431,10 +429,8 @@ mod tests {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
proto::OpenBufferResponse {
|
proto::OpenBufferResponse {
|
||||||
buffer: Some(proto::Buffer {
|
buffer: Some(proto::Buffer {
|
||||||
id: 102,
|
variant: Some(proto::buffer::Variant::Id(1))
|
||||||
visible_text: "path/two content".to_string(),
|
})
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -460,9 +456,7 @@ mod tests {
|
||||||
assert_eq!(message.worktree_id, 1);
|
assert_eq!(message.worktree_id, 1);
|
||||||
proto::OpenBufferResponse {
|
proto::OpenBufferResponse {
|
||||||
buffer: Some(proto::Buffer {
|
buffer: Some(proto::Buffer {
|
||||||
id: 101,
|
variant: Some(proto::buffer::Variant::Id(0)),
|
||||||
visible_text: "path/one content".to_string(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,9 +464,7 @@ mod tests {
|
||||||
assert_eq!(message.worktree_id, 2);
|
assert_eq!(message.worktree_id, 2);
|
||||||
proto::OpenBufferResponse {
|
proto::OpenBufferResponse {
|
||||||
buffer: Some(proto::Buffer {
|
buffer: Some(proto::Buffer {
|
||||||
id: 102,
|
variant: Some(proto::buffer::Variant::Id(1)),
|
||||||
visible_text: "path/two content".to_string(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1168,6 +1168,7 @@ mod tests {
|
||||||
use gpui::{executor, ModelHandle, TestAppContext};
|
use gpui::{executor, ModelHandle, TestAppContext};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use postage::{mpsc, watch};
|
use postage::{mpsc, watch};
|
||||||
|
use rand::prelude::*;
|
||||||
use rpc::PeerId;
|
use rpc::PeerId;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use sqlx::types::time::OffsetDateTime;
|
use sqlx::types::time::OffsetDateTime;
|
||||||
|
@ -2507,10 +2508,11 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test(iterations = 100, seed = 1)]
|
#[gpui::test]
|
||||||
async fn test_open_buffer_while_getting_definition_pointing_to_it(
|
async fn test_open_buffer_while_getting_definition_pointing_to_it(
|
||||||
mut cx_a: TestAppContext,
|
mut cx_a: TestAppContext,
|
||||||
mut cx_b: TestAppContext,
|
mut cx_b: TestAppContext,
|
||||||
|
mut rng: StdRng,
|
||||||
) {
|
) {
|
||||||
cx_a.foreground().forbid_parking();
|
cx_a.foreground().forbid_parking();
|
||||||
let mut lang_registry = Arc::new(LanguageRegistry::new());
|
let mut lang_registry = Arc::new(LanguageRegistry::new());
|
||||||
|
@ -2589,7 +2591,18 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let definitions = project_b.update(&mut cx_b, |p, cx| p.definition(&buffer_b1, 23, cx));
|
let definitions;
|
||||||
|
let buffer_b2;
|
||||||
|
if rng.gen() {
|
||||||
|
definitions = project_b.update(&mut cx_b, |p, cx| p.definition(&buffer_b1, 23, cx));
|
||||||
|
buffer_b2 =
|
||||||
|
project_b.update(&mut cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx));
|
||||||
|
} else {
|
||||||
|
buffer_b2 =
|
||||||
|
project_b.update(&mut cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx));
|
||||||
|
definitions = project_b.update(&mut cx_b, |p, cx| p.definition(&buffer_b1, 23, cx));
|
||||||
|
}
|
||||||
|
|
||||||
let (request_id, _) = fake_language_server
|
let (request_id, _) = fake_language_server
|
||||||
.receive_request::<lsp::request::GotoDefinition>()
|
.receive_request::<lsp::request::GotoDefinition>()
|
||||||
.await;
|
.await;
|
||||||
|
@ -2603,10 +2616,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let buffer_b2 = project_b
|
let buffer_b2 = buffer_b2.await.unwrap();
|
||||||
.update(&mut cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let definitions = definitions.await.unwrap();
|
let definitions = definitions.await.unwrap();
|
||||||
assert_eq!(definitions.len(), 1);
|
assert_eq!(definitions.len(), 1);
|
||||||
assert_eq!(definitions[0].target_buffer, buffer_b2);
|
assert_eq!(definitions[0].target_buffer, buffer_b2);
|
||||||
|
|
Loading…
Reference in a new issue