Fix race condition between auto-indent and on-type-formatting (#32005)
This PR addresses to fix (#31308) a race condition where auto-indent (in buffer.cs) and on-type-formatting (in lsp_store.rs) concurrently calculate indentation using the same buffer snapshot. Previous Solution (Abandoned): https://github.com/zed-industries/zed/pull/31340 Final Solution: Delay applying on-type-formatting until auto-indent is complete. Issue: If AutoindentMode finishes first, formatting works correctly. If "Formatting on typing" starts before AutoindentMode completes, it results in double indentation. Closes #31308 Release Notes: - Fixed a race condition resulting in incorrect buffer contents when combining auto-indent and on-type-formatting
This commit is contained in:
parent
d34d4f2ef1
commit
36eebb7ba8
5 changed files with 97 additions and 14 deletions
|
@ -14551,6 +14551,58 @@ async fn test_on_type_formatting_not_triggered(cx: &mut TestAppContext) {
|
|||
});
|
||||
}
|
||||
|
||||
#[gpui::test(iterations = 20, seeds(31))]
|
||||
async fn test_on_type_formatting_is_applied_after_autoindent(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let mut cx = EditorLspTestContext::new_rust(
|
||||
lsp::ServerCapabilities {
|
||||
document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
|
||||
first_trigger_character: ".".to_string(),
|
||||
more_trigger_character: None,
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
cx.update_buffer(|buffer, _| {
|
||||
// This causes autoindent to be async.
|
||||
buffer.set_sync_parse_timeout(Duration::ZERO)
|
||||
});
|
||||
|
||||
cx.set_state("fn c() {\n d()ˇ\n}\n");
|
||||
cx.simulate_keystroke("\n");
|
||||
cx.run_until_parked();
|
||||
|
||||
let buffer_cloned =
|
||||
cx.multibuffer(|multi_buffer, _| multi_buffer.as_singleton().unwrap().clone());
|
||||
let mut request =
|
||||
cx.set_request_handler::<lsp::request::OnTypeFormatting, _, _>(move |_, _, mut cx| {
|
||||
let buffer_cloned = buffer_cloned.clone();
|
||||
async move {
|
||||
buffer_cloned.update(&mut cx, |buffer, _| {
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"fn c() {\n d()\n .\n}\n",
|
||||
"OnTypeFormatting should triggered after autoindent applied"
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(Some(vec![]))
|
||||
}
|
||||
});
|
||||
|
||||
cx.simulate_keystroke(".");
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.assert_editor_state("fn c() {\n d()\n .ˇ\n}\n");
|
||||
assert!(request.next().await.is_some());
|
||||
request.close();
|
||||
assert!(request.next().await.is_none());
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_language_server_restart_due_to_settings_change(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
|
|
@ -351,7 +351,7 @@ impl EditorLspTestContext {
|
|||
T: 'static + request::Request,
|
||||
T::Params: 'static + Send,
|
||||
F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncApp) -> Fut,
|
||||
Fut: 'static + Send + Future<Output = Result<T::Result>>,
|
||||
Fut: 'static + Future<Output = Result<T::Result>>,
|
||||
{
|
||||
let url = self.buffer_lsp_url.clone();
|
||||
self.lsp.set_request_handler::<T, _, _>(move |params, cx| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue