language: Defer auto-indent until parsing catches up (#62024)
# Objective Prevent auto-indent from using stale syntax when text changes during a background parse. ## Solution Keep auto-indent pending and parsing active until the current parse completes. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Editor: Fixed auto-indent occasionally using stale syntax after rapid edits.
This commit is contained in:
1 parent
2c60a17676
commit
3917caa9a0
3 files changed
+31
-7
No files matched your search
@@ -35072,7 +35072,10 @@ async fn test_indent_after_input_for_bash(cx: &mut TestAppContext) {
|
||||
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
let language = languages::language("bash", tree_sitter_bash::LANGUAGE.into());
|
||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
||||
cx.update_buffer(|buffer, cx| {
|
||||
buffer.set_language(Some(language), cx);
|
||||
buffer.set_sync_parse_timeout(None);
|
||||
});
|
||||
|
||||
// test indents on comment insert
|
||||
cx.set_state(indoc! {"
|
||||
|
||||
@@ -1874,7 +1874,12 @@ impl Buffer {
|
||||
language.clone(),
|
||||
sync_parse_timeout,
|
||||
) {
|
||||
self.did_finish_parsing(syntax_snapshot, Some(Duration::from_millis(300)), cx);
|
||||
self.did_finish_parsing(
|
||||
syntax_snapshot,
|
||||
Some(Duration::from_millis(300)),
|
||||
false,
|
||||
cx,
|
||||
);
|
||||
self.reparse = None;
|
||||
return;
|
||||
}
|
||||
@@ -1906,7 +1911,7 @@ impl Buffer {
|
||||
let parse_again = this.version.changed_since(&parsed_version)
|
||||
|| language_registry_changed()
|
||||
|| grammar_changed();
|
||||
this.did_finish_parsing(new_syntax_map, None, cx);
|
||||
this.did_finish_parsing(new_syntax_map, None, parse_again, cx);
|
||||
this.reparse = None;
|
||||
if parse_again {
|
||||
this.reparse(cx, false);
|
||||
@@ -1920,13 +1925,21 @@ impl Buffer {
|
||||
&mut self,
|
||||
syntax_snapshot: SyntaxSnapshot,
|
||||
block_budget: Option<Duration>,
|
||||
parse_again: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.non_text_state_update_count += 1;
|
||||
self.syntax_map.lock().did_parse(syntax_snapshot);
|
||||
self.was_changed();
|
||||
self.request_autoindent(cx, block_budget);
|
||||
self.parse_status.0.send(ParseStatus::Idle).unwrap();
|
||||
|
||||
let parsing_complete = !parse_again || self.language.is_none();
|
||||
if self.language.is_none() {
|
||||
self.syntax_map.lock().clear(&self.text);
|
||||
}
|
||||
if parsing_complete {
|
||||
self.request_autoindent(cx, block_budget);
|
||||
self.parse_status.0.send(ParseStatus::Idle).unwrap();
|
||||
}
|
||||
Self::invalidate_tree_sitter_data(&mut self.tree_sitter_data, &self.text.snapshot());
|
||||
cx.emit(BufferEvent::Reparsed);
|
||||
cx.notify();
|
||||
@@ -3473,7 +3486,7 @@ impl Buffer {
|
||||
self.text.fast_forward(edited.text);
|
||||
if edited.snapshot.language == self.language {
|
||||
self.reparse = None;
|
||||
self.did_finish_parsing(edited.snapshot.syntax, None, cx);
|
||||
self.did_finish_parsing(edited.snapshot.syntax, None, false, cx);
|
||||
if did_edit {
|
||||
cx.emit(BufferEvent::Edited {
|
||||
source: BufferEditSource::User,
|
||||
|
||||
@@ -232,7 +232,15 @@ mod tests {
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
let buffer = cx.new(|cx| language::Buffer::local(text, cx).with_language(language, cx));
|
||||
let buffer = cx.new(|cx| {
|
||||
let mut buffer = language::Buffer::local(text, cx);
|
||||
buffer.set_sync_parse_timeout(None);
|
||||
buffer.set_language(Some(language), cx);
|
||||
buffer
|
||||
});
|
||||
buffer
|
||||
.read_with(cx, |buffer, _| buffer.parsing_idle())
|
||||
.await;
|
||||
let outline = buffer.read_with(cx, |buffer, _| buffer.snapshot().outline(None));
|
||||
assert_eq!(
|
||||
outline
|
||||
|
||||
Reference in new issue
Block a user