Merge remote-tracking branch 'origin/main' into fewer-context-traits
This commit is contained in:
commit
7ca412ade3
81 changed files with 1578 additions and 654 deletions
|
@ -93,7 +93,7 @@ pub trait Item {
|
|||
pub struct Project {
|
||||
worktrees: Vec<WorktreeHandle>,
|
||||
active_entry: Option<ProjectEntryId>,
|
||||
buffer_changes_tx: mpsc::UnboundedSender<BufferMessage>,
|
||||
buffer_ordered_messages_tx: mpsc::UnboundedSender<BufferOrderedMessage>,
|
||||
languages: Arc<LanguageRegistry>,
|
||||
language_servers: HashMap<LanguageServerId, LanguageServerState>,
|
||||
language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>,
|
||||
|
@ -137,11 +137,16 @@ struct LspBufferSnapshot {
|
|||
snapshot: TextBufferSnapshot,
|
||||
}
|
||||
|
||||
enum BufferMessage {
|
||||
/// Message ordered with respect to buffer operations
|
||||
enum BufferOrderedMessage {
|
||||
Operation {
|
||||
buffer_id: u64,
|
||||
operation: proto::Operation,
|
||||
},
|
||||
LanguageServerUpdate {
|
||||
language_server_id: LanguageServerId,
|
||||
message: proto::update_language_server::Variant,
|
||||
},
|
||||
Resync,
|
||||
}
|
||||
|
||||
|
@ -185,6 +190,8 @@ pub struct Collaborator {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Event {
|
||||
LanguageServerAdded(LanguageServerId),
|
||||
LanguageServerRemoved(LanguageServerId),
|
||||
ActiveEntryChanged(Option<ProjectEntryId>),
|
||||
WorktreeAdded,
|
||||
WorktreeRemoved(WorktreeId),
|
||||
|
@ -441,11 +448,11 @@ impl Project {
|
|||
) -> ModelHandle<Self> {
|
||||
cx.add_model(|cx: &mut ModelContext<Self>| {
|
||||
let (tx, rx) = mpsc::unbounded();
|
||||
cx.spawn_weak(|this, cx| Self::send_buffer_messages(this, rx, cx))
|
||||
cx.spawn_weak(|this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
|
||||
.detach();
|
||||
Self {
|
||||
worktrees: Default::default(),
|
||||
buffer_changes_tx: tx,
|
||||
buffer_ordered_messages_tx: tx,
|
||||
collaborators: Default::default(),
|
||||
opened_buffers: Default::default(),
|
||||
shared_buffers: Default::default(),
|
||||
|
@ -509,11 +516,11 @@ impl Project {
|
|||
}
|
||||
|
||||
let (tx, rx) = mpsc::unbounded();
|
||||
cx.spawn_weak(|this, cx| Self::send_buffer_messages(this, rx, cx))
|
||||
cx.spawn_weak(|this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
|
||||
.detach();
|
||||
let mut this = Self {
|
||||
worktrees: Vec::new(),
|
||||
buffer_changes_tx: tx,
|
||||
buffer_ordered_messages_tx: tx,
|
||||
loading_buffers_by_path: Default::default(),
|
||||
opened_buffer: watch::channel(),
|
||||
shared_buffers: Default::default(),
|
||||
|
@ -1166,8 +1173,8 @@ impl Project {
|
|||
)
|
||||
})
|
||||
.collect();
|
||||
self.buffer_changes_tx
|
||||
.unbounded_send(BufferMessage::Resync)
|
||||
self.buffer_ordered_messages_tx
|
||||
.unbounded_send(BufferOrderedMessage::Resync)
|
||||
.unwrap();
|
||||
cx.notify();
|
||||
Ok(())
|
||||
|
@ -1782,23 +1789,49 @@ impl Project {
|
|||
}
|
||||
}
|
||||
|
||||
async fn send_buffer_messages(
|
||||
async fn send_buffer_ordered_messages(
|
||||
this: WeakModelHandle<Self>,
|
||||
rx: UnboundedReceiver<BufferMessage>,
|
||||
rx: UnboundedReceiver<BufferOrderedMessage>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Option<()> {
|
||||
const MAX_BATCH_SIZE: usize = 128;
|
||||
|
||||
let mut needs_resync_with_host = false;
|
||||
let mut operations_by_buffer_id = HashMap::default();
|
||||
async fn flush_operations(
|
||||
this: &ModelHandle<Project>,
|
||||
operations_by_buffer_id: &mut HashMap<u64, Vec<proto::Operation>>,
|
||||
needs_resync_with_host: &mut bool,
|
||||
is_local: bool,
|
||||
cx: &AsyncAppContext,
|
||||
) {
|
||||
for (buffer_id, operations) in operations_by_buffer_id.drain() {
|
||||
let request = this.read_with(cx, |this, _| {
|
||||
let project_id = this.remote_id()?;
|
||||
Some(this.client.request(proto::UpdateBuffer {
|
||||
buffer_id,
|
||||
project_id,
|
||||
operations,
|
||||
}))
|
||||
});
|
||||
if let Some(request) = request {
|
||||
if request.await.is_err() && !is_local {
|
||||
*needs_resync_with_host = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut needs_resync_with_host = false;
|
||||
let mut changes = rx.ready_chunks(MAX_BATCH_SIZE);
|
||||
|
||||
while let Some(changes) = changes.next().await {
|
||||
let this = this.upgrade(&mut cx)?;
|
||||
let is_local = this.read_with(&cx, |this, _| this.is_local());
|
||||
|
||||
for change in changes {
|
||||
match change {
|
||||
BufferMessage::Operation {
|
||||
BufferOrderedMessage::Operation {
|
||||
buffer_id,
|
||||
operation,
|
||||
} => {
|
||||
|
@ -1811,7 +1844,8 @@ impl Project {
|
|||
.or_insert(Vec::new())
|
||||
.push(operation);
|
||||
}
|
||||
BufferMessage::Resync => {
|
||||
|
||||
BufferOrderedMessage::Resync => {
|
||||
operations_by_buffer_id.clear();
|
||||
if this
|
||||
.update(&mut cx, |this, cx| this.synchronize_remote_buffers(cx))
|
||||
|
@ -1821,25 +1855,43 @@ impl Project {
|
|||
needs_resync_with_host = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (buffer_id, operations) in operations_by_buffer_id.drain() {
|
||||
let request = this.read_with(&cx, |this, _| {
|
||||
let project_id = this.remote_id()?;
|
||||
Some(this.client.request(proto::UpdateBuffer {
|
||||
buffer_id,
|
||||
project_id,
|
||||
operations,
|
||||
}))
|
||||
});
|
||||
if let Some(request) = request {
|
||||
if request.await.is_err() && !is_local {
|
||||
needs_resync_with_host = true;
|
||||
break;
|
||||
BufferOrderedMessage::LanguageServerUpdate {
|
||||
language_server_id,
|
||||
message,
|
||||
} => {
|
||||
flush_operations(
|
||||
&this,
|
||||
&mut operations_by_buffer_id,
|
||||
&mut needs_resync_with_host,
|
||||
is_local,
|
||||
&cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
this.read_with(&cx, |this, _| {
|
||||
if let Some(project_id) = this.remote_id() {
|
||||
this.client
|
||||
.send(proto::UpdateLanguageServer {
|
||||
project_id,
|
||||
language_server_id: language_server_id.0 as u64,
|
||||
variant: Some(message),
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flush_operations(
|
||||
&this,
|
||||
&mut operations_by_buffer_id,
|
||||
&mut needs_resync_with_host,
|
||||
is_local,
|
||||
&cx,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
None
|
||||
|
@ -1853,8 +1905,8 @@ impl Project {
|
|||
) -> Option<()> {
|
||||
match event {
|
||||
BufferEvent::Operation(operation) => {
|
||||
self.buffer_changes_tx
|
||||
.unbounded_send(BufferMessage::Operation {
|
||||
self.buffer_ordered_messages_tx
|
||||
.unbounded_send(BufferOrderedMessage::Operation {
|
||||
buffer_id: buffer.read(cx).remote_id(),
|
||||
operation: language::proto::serialize_operation(operation),
|
||||
})
|
||||
|
@ -1869,7 +1921,7 @@ impl Project {
|
|||
let next_snapshot = buffer.text_snapshot();
|
||||
|
||||
let language_servers: Vec<_> = self
|
||||
.language_servers_iter_for_buffer(buffer, cx)
|
||||
.language_servers_for_buffer(buffer, cx)
|
||||
.map(|i| i.1.clone())
|
||||
.collect();
|
||||
|
||||
|
@ -1960,19 +2012,24 @@ impl Project {
|
|||
Duration::from_secs(1);
|
||||
|
||||
let task = cx.spawn_weak(|this, mut cx| async move {
|
||||
cx.background().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await;
|
||||
if let Some(this) = this.upgrade(&cx) {
|
||||
this.update(&mut cx, |this, cx | {
|
||||
this.disk_based_diagnostics_finished(language_server_id, cx);
|
||||
this.broadcast_language_server_update(
|
||||
language_server_id,
|
||||
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
|
||||
proto::LspDiskBasedDiagnosticsUpdated {},
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
cx.background().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await;
|
||||
if let Some(this) = this.upgrade(&cx) {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.disk_based_diagnostics_finished(
|
||||
language_server_id,
|
||||
cx,
|
||||
);
|
||||
this.buffer_ordered_messages_tx
|
||||
.unbounded_send(
|
||||
BufferOrderedMessage::LanguageServerUpdate {
|
||||
language_server_id,
|
||||
message:proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(Default::default())
|
||||
},
|
||||
)
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
});
|
||||
*simulate_disk_based_diagnostics_completion = Some(task);
|
||||
}
|
||||
}
|
||||
|
@ -2607,7 +2664,7 @@ impl Project {
|
|||
fn on_lsp_progress(
|
||||
&mut self,
|
||||
progress: lsp::ProgressParams,
|
||||
server_id: LanguageServerId,
|
||||
language_server_id: LanguageServerId,
|
||||
disk_based_diagnostics_progress_token: Option<String>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
|
@ -2620,7 +2677,7 @@ impl Project {
|
|||
};
|
||||
let lsp::ProgressParamsValue::WorkDone(progress) = progress.value;
|
||||
let language_server_status =
|
||||
if let Some(status) = self.language_server_statuses.get_mut(&server_id) {
|
||||
if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
|
||||
status
|
||||
} else {
|
||||
return;
|
||||
|
@ -2640,16 +2697,16 @@ impl Project {
|
|||
lsp::WorkDoneProgress::Begin(report) => {
|
||||
if is_disk_based_diagnostics_progress {
|
||||
language_server_status.has_pending_diagnostic_updates = true;
|
||||
self.disk_based_diagnostics_started(server_id, cx);
|
||||
self.broadcast_language_server_update(
|
||||
server_id,
|
||||
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
|
||||
proto::LspDiskBasedDiagnosticsUpdating {},
|
||||
),
|
||||
);
|
||||
self.disk_based_diagnostics_started(language_server_id, cx);
|
||||
self.buffer_ordered_messages_tx
|
||||
.unbounded_send(BufferOrderedMessage::LanguageServerUpdate {
|
||||
language_server_id,
|
||||
message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(Default::default())
|
||||
})
|
||||
.ok();
|
||||
} else {
|
||||
self.on_lsp_work_start(
|
||||
server_id,
|
||||
language_server_id,
|
||||
token.clone(),
|
||||
LanguageServerProgress {
|
||||
message: report.message.clone(),
|
||||
|
@ -2658,20 +2715,24 @@ impl Project {
|
|||
},
|
||||
cx,
|
||||
);
|
||||
self.broadcast_language_server_update(
|
||||
server_id,
|
||||
proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
|
||||
token,
|
||||
message: report.message,
|
||||
percentage: report.percentage.map(|p| p as u32),
|
||||
}),
|
||||
);
|
||||
self.buffer_ordered_messages_tx
|
||||
.unbounded_send(BufferOrderedMessage::LanguageServerUpdate {
|
||||
language_server_id,
|
||||
message: proto::update_language_server::Variant::WorkStart(
|
||||
proto::LspWorkStart {
|
||||
token,
|
||||
message: report.message,
|
||||
percentage: report.percentage.map(|p| p as u32),
|
||||
},
|
||||
),
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
lsp::WorkDoneProgress::Report(report) => {
|
||||
if !is_disk_based_diagnostics_progress {
|
||||
self.on_lsp_work_progress(
|
||||
server_id,
|
||||
language_server_id,
|
||||
token.clone(),
|
||||
LanguageServerProgress {
|
||||
message: report.message.clone(),
|
||||
|
@ -2680,16 +2741,18 @@ impl Project {
|
|||
},
|
||||
cx,
|
||||
);
|
||||
self.broadcast_language_server_update(
|
||||
server_id,
|
||||
proto::update_language_server::Variant::WorkProgress(
|
||||
proto::LspWorkProgress {
|
||||
token,
|
||||
message: report.message,
|
||||
percentage: report.percentage.map(|p| p as u32),
|
||||
},
|
||||
),
|
||||
);
|
||||
self.buffer_ordered_messages_tx
|
||||
.unbounded_send(BufferOrderedMessage::LanguageServerUpdate {
|
||||
language_server_id,
|
||||
message: proto::update_language_server::Variant::WorkProgress(
|
||||
proto::LspWorkProgress {
|
||||
token,
|
||||
message: report.message,
|
||||
percentage: report.percentage.map(|p| p as u32),
|
||||
},
|
||||
),
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
lsp::WorkDoneProgress::End(_) => {
|
||||
|
@ -2697,21 +2760,26 @@ impl Project {
|
|||
|
||||
if is_disk_based_diagnostics_progress {
|
||||
language_server_status.has_pending_diagnostic_updates = false;
|
||||
self.disk_based_diagnostics_finished(server_id, cx);
|
||||
self.broadcast_language_server_update(
|
||||
server_id,
|
||||
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
|
||||
proto::LspDiskBasedDiagnosticsUpdated {},
|
||||
),
|
||||
);
|
||||
self.disk_based_diagnostics_finished(language_server_id, cx);
|
||||
self.buffer_ordered_messages_tx
|
||||
.unbounded_send(BufferOrderedMessage::LanguageServerUpdate {
|
||||
language_server_id,
|
||||
message:
|
||||
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
|
||||
Default::default(),
|
||||
),
|
||||
})
|
||||
.ok();
|
||||
} else {
|
||||
self.on_lsp_work_end(server_id, token.clone(), cx);
|
||||
self.broadcast_language_server_update(
|
||||
server_id,
|
||||
proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
|
||||
token,
|
||||
}),
|
||||
);
|
||||
self.on_lsp_work_end(language_server_id, token.clone(), cx);
|
||||
self.buffer_ordered_messages_tx
|
||||
.unbounded_send(BufferOrderedMessage::LanguageServerUpdate {
|
||||
language_server_id,
|
||||
message: proto::update_language_server::Variant::WorkEnd(
|
||||
proto::LspWorkEnd { token },
|
||||
),
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2820,22 +2888,6 @@ impl Project {
|
|||
})
|
||||
}
|
||||
|
||||
fn broadcast_language_server_update(
|
||||
&self,
|
||||
language_server_id: LanguageServerId,
|
||||
event: proto::update_language_server::Variant,
|
||||
) {
|
||||
if let Some(project_id) = self.remote_id() {
|
||||
self.client
|
||||
.send(proto::UpdateLanguageServer {
|
||||
project_id,
|
||||
language_server_id: language_server_id.0 as u64,
|
||||
variant: Some(event),
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn language_server_statuses(
|
||||
&self,
|
||||
) -> impl DoubleEndedIterator<Item = &LanguageServerStatus> {
|
||||
|
@ -4864,8 +4916,8 @@ impl Project {
|
|||
if is_host {
|
||||
this.opened_buffers
|
||||
.retain(|_, buffer| !matches!(buffer, OpenBuffer::Operations(_)));
|
||||
this.buffer_changes_tx
|
||||
.unbounded_send(BufferMessage::Resync)
|
||||
this.buffer_ordered_messages_tx
|
||||
.unbounded_send(BufferOrderedMessage::Resync)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
@ -6279,7 +6331,25 @@ impl Project {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn language_servers_iter_for_buffer(
|
||||
pub fn language_servers(
|
||||
&self,
|
||||
) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName, WorktreeId)> {
|
||||
self.language_server_ids
|
||||
.iter()
|
||||
.map(|((worktree_id, server_name), server_id)| {
|
||||
(*server_id, server_name.clone(), *worktree_id)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
|
||||
if let LanguageServerState::Running { server, .. } = self.language_servers.get(&id)? {
|
||||
Some(server.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn language_servers_for_buffer(
|
||||
&self,
|
||||
buffer: &Buffer,
|
||||
cx: &AppContext,
|
||||
|
@ -6299,20 +6369,12 @@ impl Project {
|
|||
})
|
||||
}
|
||||
|
||||
fn language_servers_for_buffer(
|
||||
&self,
|
||||
buffer: &Buffer,
|
||||
cx: &AppContext,
|
||||
) -> Vec<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
|
||||
self.language_servers_iter_for_buffer(buffer, cx).collect()
|
||||
}
|
||||
|
||||
fn primary_language_servers_for_buffer(
|
||||
&self,
|
||||
buffer: &Buffer,
|
||||
cx: &AppContext,
|
||||
) -> Option<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
|
||||
self.language_servers_iter_for_buffer(buffer, cx).next()
|
||||
self.language_servers_for_buffer(buffer, cx).next()
|
||||
}
|
||||
|
||||
fn language_server_for_buffer(
|
||||
|
@ -6321,7 +6383,7 @@ impl Project {
|
|||
server_id: LanguageServerId,
|
||||
cx: &AppContext,
|
||||
) -> Option<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
|
||||
self.language_servers_iter_for_buffer(buffer, cx)
|
||||
self.language_servers_for_buffer(buffer, cx)
|
||||
.find(|(_, s)| s.server_id() == server_id)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue