@@ -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();
+ }
}
_ => {}