Send language server updates via the same task that sends buffer operations

Co-authored-by: Julia Risley <julia@zed.dev>
This commit is contained in:
Max Brunsfeld 2023-04-24 13:52:03 -07:00
parent ce34bf62fe
commit a8ddba55d8

View file

@ -142,6 +142,10 @@ enum BufferMessage {
buffer_id: u64, buffer_id: u64,
operation: proto::Operation, operation: proto::Operation,
}, },
LanguageServerUpdate {
language_server_id: LanguageServerId,
message: proto::update_language_server::Variant,
},
Resync, Resync,
} }
@ -1791,9 +1795,35 @@ impl Project {
) -> Option<()> { ) -> Option<()> {
const MAX_BATCH_SIZE: usize = 128; const MAX_BATCH_SIZE: usize = 128;
let mut needs_resync_with_host = false;
let mut operations_by_buffer_id = HashMap::default(); 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); let mut changes = rx.ready_chunks(MAX_BATCH_SIZE);
while let Some(changes) = changes.next().await { while let Some(changes) = changes.next().await {
let this = this.upgrade(&mut cx)?; let this = this.upgrade(&mut cx)?;
let is_local = this.read_with(&cx, |this, _| this.is_local()); let is_local = this.read_with(&cx, |this, _| this.is_local());
@ -1813,6 +1843,7 @@ impl Project {
.or_insert(Vec::new()) .or_insert(Vec::new())
.push(operation); .push(operation);
} }
BufferMessage::Resync => { BufferMessage::Resync => {
operations_by_buffer_id.clear(); operations_by_buffer_id.clear();
if this if this
@ -1823,25 +1854,43 @@ impl Project {
needs_resync_with_host = false; needs_resync_with_host = false;
} }
} }
}
}
for (buffer_id, operations) in operations_by_buffer_id.drain() { BufferMessage::LanguageServerUpdate {
let request = this.read_with(&cx, |this, _| { language_server_id,
let project_id = this.remote_id()?; message,
Some(this.client.request(proto::UpdateBuffer { } => {
buffer_id, flush_operations(
project_id, &this,
operations, &mut operations_by_buffer_id,
})) &mut needs_resync_with_host,
}); is_local,
if let Some(request) = request { &cx,
if request.await.is_err() && !is_local { )
needs_resync_with_host = true; .await;
break;
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 None
@ -1962,19 +2011,24 @@ impl Project {
Duration::from_secs(1); Duration::from_secs(1);
let task = cx.spawn_weak(|this, mut cx| async move { let task = cx.spawn_weak(|this, mut cx| async move {
cx.background().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await; cx.background().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await;
if let Some(this) = this.upgrade(&cx) { if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx | { this.update(&mut cx, |this, cx| {
this.disk_based_diagnostics_finished(language_server_id, cx); this.disk_based_diagnostics_finished(
this.broadcast_language_server_update( language_server_id,
language_server_id, cx,
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated( );
proto::LspDiskBasedDiagnosticsUpdated {}, this.buffer_changes_tx
), .unbounded_send(
); BufferMessage::LanguageServerUpdate {
}); language_server_id,
} message:proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(Default::default())
}); },
)
.ok();
});
}
});
*simulate_disk_based_diagnostics_completion = Some(task); *simulate_disk_based_diagnostics_completion = Some(task);
} }
} }
@ -2609,7 +2663,7 @@ impl Project {
fn on_lsp_progress( fn on_lsp_progress(
&mut self, &mut self,
progress: lsp::ProgressParams, progress: lsp::ProgressParams,
server_id: LanguageServerId, language_server_id: LanguageServerId,
disk_based_diagnostics_progress_token: Option<String>, disk_based_diagnostics_progress_token: Option<String>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) { ) {
@ -2622,7 +2676,7 @@ impl Project {
}; };
let lsp::ProgressParamsValue::WorkDone(progress) = progress.value; let lsp::ProgressParamsValue::WorkDone(progress) = progress.value;
let language_server_status = 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 status
} else { } else {
return; return;
@ -2642,16 +2696,16 @@ impl Project {
lsp::WorkDoneProgress::Begin(report) => { lsp::WorkDoneProgress::Begin(report) => {
if is_disk_based_diagnostics_progress { if is_disk_based_diagnostics_progress {
language_server_status.has_pending_diagnostic_updates = true; language_server_status.has_pending_diagnostic_updates = true;
self.disk_based_diagnostics_started(server_id, cx); self.disk_based_diagnostics_started(language_server_id, cx);
self.broadcast_language_server_update( self.buffer_changes_tx
server_id, .unbounded_send(BufferMessage::LanguageServerUpdate {
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating( language_server_id,
proto::LspDiskBasedDiagnosticsUpdating {}, message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(Default::default())
), })
); .ok();
} else { } else {
self.on_lsp_work_start( self.on_lsp_work_start(
server_id, language_server_id,
token.clone(), token.clone(),
LanguageServerProgress { LanguageServerProgress {
message: report.message.clone(), message: report.message.clone(),
@ -2660,20 +2714,24 @@ impl Project {
}, },
cx, cx,
); );
self.broadcast_language_server_update( self.buffer_changes_tx
server_id, .unbounded_send(BufferMessage::LanguageServerUpdate {
proto::update_language_server::Variant::WorkStart(proto::LspWorkStart { language_server_id,
token, message: proto::update_language_server::Variant::WorkStart(
message: report.message, proto::LspWorkStart {
percentage: report.percentage.map(|p| p as u32), token,
}), message: report.message,
); percentage: report.percentage.map(|p| p as u32),
},
),
})
.ok();
} }
} }
lsp::WorkDoneProgress::Report(report) => { lsp::WorkDoneProgress::Report(report) => {
if !is_disk_based_diagnostics_progress { if !is_disk_based_diagnostics_progress {
self.on_lsp_work_progress( self.on_lsp_work_progress(
server_id, language_server_id,
token.clone(), token.clone(),
LanguageServerProgress { LanguageServerProgress {
message: report.message.clone(), message: report.message.clone(),
@ -2682,16 +2740,18 @@ impl Project {
}, },
cx, cx,
); );
self.broadcast_language_server_update( self.buffer_changes_tx
server_id, .unbounded_send(BufferMessage::LanguageServerUpdate {
proto::update_language_server::Variant::WorkProgress( language_server_id,
proto::LspWorkProgress { message: proto::update_language_server::Variant::WorkProgress(
token, proto::LspWorkProgress {
message: report.message, token,
percentage: report.percentage.map(|p| p as u32), message: report.message,
}, percentage: report.percentage.map(|p| p as u32),
), },
); ),
})
.ok();
} }
} }
lsp::WorkDoneProgress::End(_) => { lsp::WorkDoneProgress::End(_) => {
@ -2699,21 +2759,26 @@ impl Project {
if is_disk_based_diagnostics_progress { if is_disk_based_diagnostics_progress {
language_server_status.has_pending_diagnostic_updates = false; language_server_status.has_pending_diagnostic_updates = false;
self.disk_based_diagnostics_finished(server_id, cx); self.disk_based_diagnostics_finished(language_server_id, cx);
self.broadcast_language_server_update( self.buffer_changes_tx
server_id, .unbounded_send(BufferMessage::LanguageServerUpdate {
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated( language_server_id,
proto::LspDiskBasedDiagnosticsUpdated {}, message:
), proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
); Default::default(),
),
})
.ok();
} else { } else {
self.on_lsp_work_end(server_id, token.clone(), cx); self.on_lsp_work_end(language_server_id, token.clone(), cx);
self.broadcast_language_server_update( self.buffer_changes_tx
server_id, .unbounded_send(BufferMessage::LanguageServerUpdate {
proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { language_server_id,
token, message: proto::update_language_server::Variant::WorkEnd(
}), proto::LspWorkEnd { token },
); ),
})
.ok();
} }
} }
} }
@ -2822,22 +2887,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( pub fn language_server_statuses(
&self, &self,
) -> impl DoubleEndedIterator<Item = &LanguageServerStatus> { ) -> impl DoubleEndedIterator<Item = &LanguageServerStatus> {