Port buffer reload bug fixes back to gpui1 crates

This commit is contained in:
Max Brunsfeld 2023-11-16 16:01:49 -08:00
parent 5f1acae0d3
commit 0bed5e4562
5 changed files with 67 additions and 55 deletions

View file

@ -1051,17 +1051,15 @@ mod tests {
); );
// Ensure updates to the file are reflected in the LSP. // Ensure updates to the file are reflected in the LSP.
buffer_1 buffer_1.update(cx, |buffer, cx| {
.update(cx, |buffer, cx| { buffer.file_updated(
buffer.file_updated( Arc::new(File {
Arc::new(File { abs_path: "/root/child/buffer-1".into(),
abs_path: "/root/child/buffer-1".into(), path: Path::new("child/buffer-1").into(),
path: Path::new("child/buffer-1").into(), }),
}), cx,
cx, )
) });
})
.await;
assert_eq!( assert_eq!(
lsp.receive_notification::<lsp::notification::DidCloseTextDocument>() lsp.receive_notification::<lsp::notification::DidCloseTextDocument>()
.await, .await,

View file

@ -17,7 +17,7 @@ use crate::{
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
pub use clock::ReplicaId; pub use clock::ReplicaId;
use futures::FutureExt as _; use futures::channel::oneshot;
use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, Task}; use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, Task};
use lsp::LanguageServerId; use lsp::LanguageServerId;
use parking_lot::Mutex; use parking_lot::Mutex;
@ -45,7 +45,7 @@ pub use text::{Buffer as TextBuffer, BufferSnapshot as TextBufferSnapshot, *};
use theme::SyntaxTheme; use theme::SyntaxTheme;
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
use util::RandomCharIter; use util::RandomCharIter;
use util::{RangeExt, TryFutureExt as _}; use util::RangeExt;
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub use {tree_sitter_rust, tree_sitter_typescript}; pub use {tree_sitter_rust, tree_sitter_typescript};
@ -62,6 +62,7 @@ pub struct Buffer {
saved_mtime: SystemTime, saved_mtime: SystemTime,
transaction_depth: usize, transaction_depth: usize,
was_dirty_before_starting_transaction: Option<bool>, was_dirty_before_starting_transaction: Option<bool>,
reload_task: Option<Task<Result<()>>>,
language: Option<Arc<Language>>, language: Option<Arc<Language>>,
autoindent_requests: Vec<Arc<AutoindentRequest>>, autoindent_requests: Vec<Arc<AutoindentRequest>>,
pending_autoindent: Option<Task<()>>, pending_autoindent: Option<Task<()>>,
@ -509,6 +510,7 @@ impl Buffer {
saved_mtime, saved_mtime,
saved_version: buffer.version(), saved_version: buffer.version(),
saved_version_fingerprint: buffer.as_rope().fingerprint(), saved_version_fingerprint: buffer.as_rope().fingerprint(),
reload_task: None,
transaction_depth: 0, transaction_depth: 0,
was_dirty_before_starting_transaction: None, was_dirty_before_starting_transaction: None,
text: buffer, text: buffer,
@ -608,37 +610,52 @@ impl Buffer {
cx.notify(); cx.notify();
} }
pub fn reload(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<Option<Transaction>>> { pub fn reload(
cx.spawn(|this, mut cx| async move { &mut self,
if let Some((new_mtime, new_text)) = this.read_with(&cx, |this, cx| { cx: &mut ModelContext<Self>,
) -> oneshot::Receiver<Option<Transaction>> {
let (tx, rx) = futures::channel::oneshot::channel();
let prev_version = self.text.version();
self.reload_task = Some(cx.spawn(|this, mut cx| async move {
let Some((new_mtime, new_text)) = this.update(&mut cx, |this, cx| {
let file = this.file.as_ref()?.as_local()?; let file = this.file.as_ref()?.as_local()?;
Some((file.mtime(), file.load(cx))) Some((file.mtime(), file.load(cx)))
}) { }) else {
let new_text = new_text.await?; return Ok(());
let diff = this };
.read_with(&cx, |this, cx| this.diff(new_text, cx))
.await; let new_text = new_text.await?;
this.update(&mut cx, |this, cx| { let diff = this
if this.version() == diff.base_version { .update(&mut cx, |this, cx| this.diff(new_text.clone(), cx))
this.finalize_last_transaction(); .await;
this.apply_diff(diff, cx); this.update(&mut cx, |this, cx| {
if let Some(transaction) = this.finalize_last_transaction().cloned() { if this.version() == diff.base_version {
this.did_reload( this.finalize_last_transaction();
this.version(), this.apply_diff(diff, cx);
this.as_rope().fingerprint(), tx.send(this.finalize_last_transaction().cloned()).ok();
this.line_ending(),
new_mtime, this.did_reload(
cx, this.version(),
); this.as_rope().fingerprint(),
return Ok(Some(transaction)); this.line_ending(),
} new_mtime,
} cx,
Ok(None) );
}) } else {
} else { this.did_reload(
Ok(None) prev_version,
} Rope::text_fingerprint(&new_text),
}) this.line_ending(),
new_mtime,
cx,
);
}
this.reload_task.take();
});
Ok(())
}));
rx
} }
pub fn did_reload( pub fn did_reload(
@ -667,13 +684,8 @@ impl Buffer {
cx.notify(); cx.notify();
} }
pub fn file_updated( pub fn file_updated(&mut self, new_file: Arc<dyn File>, cx: &mut ModelContext<Self>) {
&mut self,
new_file: Arc<dyn File>,
cx: &mut ModelContext<Self>,
) -> Task<()> {
let mut file_changed = false; let mut file_changed = false;
let mut task = Task::ready(());
if let Some(old_file) = self.file.as_ref() { if let Some(old_file) = self.file.as_ref() {
if new_file.path() != old_file.path() { if new_file.path() != old_file.path() {
@ -693,8 +705,7 @@ impl Buffer {
file_changed = true; file_changed = true;
if !self.is_dirty() { if !self.is_dirty() {
let reload = self.reload(cx).log_err().map(drop); self.reload(cx).close();
task = cx.foreground().spawn(reload);
} }
} }
} }
@ -708,7 +719,6 @@ impl Buffer {
cx.emit(Event::FileHandleChanged); cx.emit(Event::FileHandleChanged);
cx.notify(); cx.notify();
} }
task
} }
pub fn diff_base(&self) -> Option<&str> { pub fn diff_base(&self) -> Option<&str> {

View file

@ -6190,7 +6190,7 @@ impl Project {
.log_err(); .log_err();
} }
buffer.file_updated(Arc::new(new_file), cx).detach(); buffer.file_updated(Arc::new(new_file), cx);
} }
} }
}); });
@ -7182,7 +7182,7 @@ impl Project {
.ok_or_else(|| anyhow!("no such worktree"))?; .ok_or_else(|| anyhow!("no such worktree"))?;
let file = File::from_proto(file, worktree, cx)?; let file = File::from_proto(file, worktree, cx)?;
buffer.update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {
buffer.file_updated(Arc::new(file), cx).detach(); buffer.file_updated(Arc::new(file), cx);
}); });
this.detect_language_for_buffer(&buffer, cx); this.detect_language_for_buffer(&buffer, cx);
} }

View file

@ -959,7 +959,7 @@ impl LocalWorktree {
buffer_handle.update(&mut cx, |buffer, cx| { buffer_handle.update(&mut cx, |buffer, cx| {
if has_changed_file { if has_changed_file {
buffer.file_updated(new_file, cx).detach(); buffer.file_updated(new_file, cx);
} }
}); });
} }

View file

@ -41,6 +41,10 @@ impl Rope {
Self::default() Self::default()
} }
pub fn text_fingerprint(text: &str) -> RopeFingerprint {
bromberg_sl2::hash_strict(text.as_bytes())
}
pub fn append(&mut self, rope: Rope) { pub fn append(&mut self, rope: Rope) {
let mut chunks = rope.chunks.cursor::<()>(); let mut chunks = rope.chunks.cursor::<()>();
chunks.next(&()); chunks.next(&());
@ -931,7 +935,7 @@ impl<'a> From<&'a str> for ChunkSummary {
fn from(text: &'a str) -> Self { fn from(text: &'a str) -> Self {
Self { Self {
text: TextSummary::from(text), text: TextSummary::from(text),
fingerprint: bromberg_sl2::hash_strict(text.as_bytes()), fingerprint: Rope::text_fingerprint(text),
} }
} }
} }