mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
Avoid racing git diffs & allow for "as fast as possible" diff updating
Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
parent
b18dd8fcff
commit
a679557e40
@ -74,6 +74,10 @@
|
||||
"hard_tabs": false,
|
||||
// How many columns a tab should occupy.
|
||||
"tab_size": 4,
|
||||
// Git gutter behavior configuration. Remove this item to disable git gutters entirely.
|
||||
"git_gutter": {
|
||||
"files_included": "all"
|
||||
},
|
||||
// Settings specific to the terminal
|
||||
"terminal": {
|
||||
// What shell to use when opening a terminal. May take 3 values:
|
||||
|
@ -46,10 +46,16 @@ pub use {tree_sitter_rust, tree_sitter_typescript};
|
||||
|
||||
pub use lsp::DiagnosticSeverity;
|
||||
|
||||
struct GitDiffStatus {
|
||||
diff: git::BufferDiff,
|
||||
update_in_progress: bool,
|
||||
update_requested: bool,
|
||||
}
|
||||
|
||||
pub struct Buffer {
|
||||
text: TextBuffer,
|
||||
head_text: Option<Arc<String>>,
|
||||
git_diff: git::BufferDiff,
|
||||
git_diff_status: GitDiffStatus,
|
||||
file: Option<Arc<dyn File>>,
|
||||
saved_version: clock::Global,
|
||||
saved_version_fingerprint: String,
|
||||
@ -77,7 +83,7 @@ pub struct Buffer {
|
||||
|
||||
pub struct BufferSnapshot {
|
||||
text: text::BufferSnapshot,
|
||||
pub git_diff_snapshot: git::BufferDiff,
|
||||
pub git_diff: git::BufferDiff,
|
||||
pub(crate) syntax: SyntaxSnapshot,
|
||||
file: Option<Arc<dyn File>>,
|
||||
diagnostics: DiagnosticSet,
|
||||
@ -433,7 +439,11 @@ impl Buffer {
|
||||
was_dirty_before_starting_transaction: None,
|
||||
text: buffer,
|
||||
head_text,
|
||||
git_diff: git::BufferDiff::new(),
|
||||
git_diff_status: GitDiffStatus {
|
||||
diff: git::BufferDiff::new(),
|
||||
update_in_progress: false,
|
||||
update_requested: false,
|
||||
},
|
||||
file,
|
||||
syntax_map: Mutex::new(SyntaxMap::new()),
|
||||
parsing_in_background: false,
|
||||
@ -464,7 +474,7 @@ impl Buffer {
|
||||
BufferSnapshot {
|
||||
text,
|
||||
syntax,
|
||||
git_diff_snapshot: self.git_diff.clone(),
|
||||
git_diff: self.git_diff_status.diff.clone(),
|
||||
file: self.file.clone(),
|
||||
remote_selections: self.remote_selections.clone(),
|
||||
diagnostics: self.diagnostics.clone(),
|
||||
@ -653,15 +663,20 @@ impl Buffer {
|
||||
}
|
||||
|
||||
pub fn needs_git_update(&self) -> bool {
|
||||
self.git_diff.needs_update(self)
|
||||
self.git_diff_status.diff.needs_update(self)
|
||||
}
|
||||
|
||||
pub fn update_git(&mut self, cx: &mut ModelContext<Self>) {
|
||||
if self.git_diff_status.update_in_progress {
|
||||
self.git_diff_status.update_requested = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(head_text) = &self.head_text {
|
||||
let snapshot = self.snapshot();
|
||||
let head_text = head_text.clone();
|
||||
|
||||
let mut diff = self.git_diff.clone();
|
||||
let mut diff = self.git_diff_status.diff.clone();
|
||||
let diff = cx.background().spawn(async move {
|
||||
diff.update(&head_text, &snapshot).await;
|
||||
diff
|
||||
@ -671,9 +686,14 @@ impl Buffer {
|
||||
let buffer_diff = diff.await;
|
||||
if let Some(this) = this.upgrade(&cx) {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.git_diff = buffer_diff;
|
||||
this.git_diff_status.diff = buffer_diff;
|
||||
this.git_diff_update_count += 1;
|
||||
cx.notify();
|
||||
|
||||
this.git_diff_status.update_in_progress = false;
|
||||
if this.git_diff_status.update_requested {
|
||||
this.update_git(cx);
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -2195,7 +2215,7 @@ impl BufferSnapshot {
|
||||
&'a self,
|
||||
query_row_range: Range<u32>,
|
||||
) -> impl 'a + Iterator<Item = git::DiffHunk<u32>> {
|
||||
self.git_diff_snapshot.hunks_in_range(query_row_range, self)
|
||||
self.git_diff.hunks_in_range(query_row_range, self)
|
||||
}
|
||||
|
||||
pub fn diagnostics_in_range<'a, T, O>(
|
||||
@ -2275,7 +2295,7 @@ impl Clone for BufferSnapshot {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
text: self.text.clone(),
|
||||
git_diff_snapshot: self.git_diff_snapshot.clone(),
|
||||
git_diff: self.git_diff.clone(),
|
||||
syntax: self.syntax.clone(),
|
||||
file: self.file.clone(),
|
||||
remote_selections: self.remote_selections.clone(),
|
||||
|
@ -61,6 +61,22 @@ pub struct EditorSettings {
|
||||
pub format_on_save: Option<FormatOnSave>,
|
||||
pub formatter: Option<Formatter>,
|
||||
pub enable_language_server: Option<bool>,
|
||||
pub git_gutter: Option<GitGutterConfig>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, JsonSchema)]
|
||||
pub struct GitGutterConfig {
|
||||
pub files_included: GitGutterLevel,
|
||||
pub debounce_delay_millis: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum GitGutterLevel {
|
||||
#[default]
|
||||
All,
|
||||
OnlyTracked,
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
@ -250,6 +266,7 @@ impl Settings {
|
||||
format_on_save: required(defaults.editor.format_on_save),
|
||||
formatter: required(defaults.editor.formatter),
|
||||
enable_language_server: required(defaults.editor.enable_language_server),
|
||||
git_gutter: defaults.editor.git_gutter,
|
||||
},
|
||||
editor_overrides: Default::default(),
|
||||
terminal_defaults: Default::default(),
|
||||
@ -378,6 +395,7 @@ impl Settings {
|
||||
format_on_save: Some(FormatOnSave::On),
|
||||
formatter: Some(Formatter::LanguageServer),
|
||||
enable_language_server: Some(true),
|
||||
git_gutter: Default::default(),
|
||||
},
|
||||
editor_overrides: Default::default(),
|
||||
terminal_defaults: Default::default(),
|
||||
|
@ -734,18 +734,41 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
|
||||
);
|
||||
}
|
||||
|
||||
const GIT_DELAY: Duration = Duration::from_millis(10);
|
||||
let debounce_delay = cx
|
||||
.global::<Settings>()
|
||||
.editor_overrides
|
||||
.git_gutter
|
||||
.unwrap_or_default()
|
||||
.debounce_delay_millis;
|
||||
let item = item.clone();
|
||||
pending_git_update.fire_new(
|
||||
GIT_DELAY,
|
||||
workspace,
|
||||
cx,
|
||||
|project, mut cx| async move {
|
||||
cx.update(|cx| item.update_git(project, cx))
|
||||
.await
|
||||
.log_err();
|
||||
},
|
||||
);
|
||||
|
||||
if let Some(delay) = debounce_delay {
|
||||
const MIN_GIT_DELAY: u64 = 50;
|
||||
|
||||
let delay = delay.max(MIN_GIT_DELAY);
|
||||
let duration = Duration::from_millis(delay);
|
||||
|
||||
pending_git_update.fire_new(
|
||||
duration,
|
||||
workspace,
|
||||
cx,
|
||||
|project, mut cx| async move {
|
||||
cx.update(|cx| item.update_git(project, cx))
|
||||
.await
|
||||
.log_err();
|
||||
},
|
||||
);
|
||||
} else {
|
||||
let project = workspace.project().downgrade();
|
||||
cx.spawn_weak(|_, mut cx| async move {
|
||||
if let Some(project) = project.upgrade(&cx) {
|
||||
cx.update(|cx| item.update_git(project, cx))
|
||||
.await
|
||||
.log_err();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
Loading…
Reference in New Issue
Block a user