mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 19:10:24 +00:00
Fix crash when restarting a language server after it reports an unknown buffer version
Co-authored-by: Antonio Scandurra <antonio@zed.dev>
This commit is contained in:
parent
a222821dfa
commit
41ff42ddec
2 changed files with 64 additions and 18 deletions
|
@ -2081,6 +2081,7 @@ impl Project {
|
||||||
.buffer_snapshots
|
.buffer_snapshots
|
||||||
.entry(buffer.remote_id())
|
.entry(buffer.remote_id())
|
||||||
.or_insert_with(|| vec![(0, buffer.text_snapshot())]);
|
.or_insert_with(|| vec![(0, buffer.text_snapshot())]);
|
||||||
|
|
||||||
let (version, initial_snapshot) = versions.last().unwrap();
|
let (version, initial_snapshot) = versions.last().unwrap();
|
||||||
let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
|
let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
|
||||||
language_server
|
language_server
|
||||||
|
@ -2617,6 +2618,7 @@ impl Project {
|
||||||
worktree_id: worktree.read(cx).id(),
|
worktree_id: worktree.read(cx).id(),
|
||||||
path: relative_path.into(),
|
path: relative_path.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(buffer) = self.get_open_buffer(&project_path, cx) {
|
if let Some(buffer) = self.get_open_buffer(&project_path, cx) {
|
||||||
self.update_buffer_diagnostics(&buffer, diagnostics.clone(), version, cx)?;
|
self.update_buffer_diagnostics(&buffer, diagnostics.clone(), version, cx)?;
|
||||||
}
|
}
|
||||||
|
@ -6124,25 +6126,20 @@ impl Project {
|
||||||
.buffer_snapshots
|
.buffer_snapshots
|
||||||
.get_mut(&buffer_id)
|
.get_mut(&buffer_id)
|
||||||
.ok_or_else(|| anyhow!("no snapshot found for buffer {}", buffer_id))?;
|
.ok_or_else(|| anyhow!("no snapshot found for buffer {}", buffer_id))?;
|
||||||
let mut found_snapshot = None;
|
let found_snapshot = snapshots
|
||||||
snapshots.retain(|(snapshot_version, snapshot)| {
|
.binary_search_by_key(&version, |e| e.0)
|
||||||
if snapshot_version + OLD_VERSIONS_TO_RETAIN < version {
|
.map(|ix| snapshots[ix].1.clone())
|
||||||
false
|
.map_err(|_| {
|
||||||
} else {
|
anyhow!(
|
||||||
if *snapshot_version == version {
|
"snapshot not found for buffer {} at version {}",
|
||||||
found_snapshot = Some(snapshot.clone());
|
buffer_id,
|
||||||
}
|
version
|
||||||
true
|
)
|
||||||
}
|
})?;
|
||||||
|
snapshots.retain(|(snapshot_version, _)| {
|
||||||
|
snapshot_version + OLD_VERSIONS_TO_RETAIN >= version
|
||||||
});
|
});
|
||||||
|
Ok(found_snapshot)
|
||||||
found_snapshot.ok_or_else(|| {
|
|
||||||
anyhow!(
|
|
||||||
"snapshot not found for buffer {} at version {}",
|
|
||||||
buffer_id,
|
|
||||||
version
|
|
||||||
)
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Ok((buffer.read(cx)).text_snapshot())
|
Ok((buffer.read(cx)).text_snapshot())
|
||||||
}
|
}
|
||||||
|
|
|
@ -806,6 +806,55 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_restarted_server_reporting_invalid_buffer_version(cx: &mut gpui::TestAppContext) {
|
||||||
|
cx.foreground().forbid_parking();
|
||||||
|
|
||||||
|
let mut language = Language::new(
|
||||||
|
LanguageConfig {
|
||||||
|
path_suffixes: vec!["rs".to_string()],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
let mut fake_servers = language
|
||||||
|
.set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
|
||||||
|
name: "the-lsp",
|
||||||
|
..Default::default()
|
||||||
|
}))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let fs = FakeFs::new(cx.background());
|
||||||
|
fs.insert_tree("/dir", json!({ "a.rs": "" })).await;
|
||||||
|
|
||||||
|
let project = Project::test(fs, ["/dir".as_ref()], cx).await;
|
||||||
|
project.update(cx, |project, _| project.languages.add(Arc::new(language)));
|
||||||
|
|
||||||
|
let buffer = project
|
||||||
|
.update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Before restarting the server, report diagnostics with an unknown buffer version.
|
||||||
|
let fake_server = fake_servers.next().await.unwrap();
|
||||||
|
fake_server.notify::<lsp::notification::PublishDiagnostics>(lsp::PublishDiagnosticsParams {
|
||||||
|
uri: lsp::Url::from_file_path("/dir/a.rs").unwrap(),
|
||||||
|
version: Some(10000),
|
||||||
|
diagnostics: Vec::new(),
|
||||||
|
});
|
||||||
|
cx.foreground().run_until_parked();
|
||||||
|
|
||||||
|
project.update(cx, |project, cx| {
|
||||||
|
project.restart_language_servers_for_buffers([buffer.clone()], cx);
|
||||||
|
});
|
||||||
|
let mut fake_server = fake_servers.next().await.unwrap();
|
||||||
|
let notification = fake_server
|
||||||
|
.receive_notification::<lsp::notification::DidOpenTextDocument>()
|
||||||
|
.await
|
||||||
|
.text_document;
|
||||||
|
assert_eq!(notification.version, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_toggling_enable_language_server(
|
async fn test_toggling_enable_language_server(
|
||||||
deterministic: Arc<Deterministic>,
|
deterministic: Arc<Deterministic>,
|
||||||
|
|
Loading…
Reference in a new issue