From 13b5c1d8aa6658098adfccee8ce75d289633802b Mon Sep 17 00:00:00 2001 From: Harsh Narayan Jha <50262541+HarshNarayanJha@users.noreply.github.com> Date: Sun, 24 Nov 2024 00:20:10 +0530 Subject: [PATCH 1/6] feat: add git blame (You) logic this commit suffixes (You) to the git blame author if `git config user.name` is same as author name `get_git_user_name` fetches user.name `for_path` method is modified to append (You) at the end of entry.author if author == username --- crates/git/src/blame.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/crates/git/src/blame.rs b/crates/git/src/blame.rs index 8f87a8ca546ee8..c3726e6f849d07 100644 --- a/crates/git/src/blame.rs +++ b/crates/git/src/blame.rs @@ -36,6 +36,18 @@ impl Blame { let mut entries = parse_git_blame(&output)?; entries.sort_unstable_by(|a, b| a.range.start.cmp(&b.range.start)); + let current_user = get_git_user_name(git_binary, working_directory)?; + + if let Some(username) = current_user { + for entry in &mut entries { + if let Some(ref author) = entry.author { + if author == &username { + entry.author = Some(format!("{} (You)", author)); + } + } + } + } + let mut permalinks = HashMap::default(); let mut unique_shas = HashSet::default(); let parsed_remote_url = remote_url @@ -119,6 +131,21 @@ fn run_git_blame( Ok(String::from_utf8(output.stdout)?) } +fn get_git_user_name(git_binary: &Path, working_directory: &Path) -> Result> { + let output = std::process::Command::new(git_binary) + .current_dir(working_directory) + .arg("config") + .arg("user.name") + .output()?; + + if output.status.success() { + let name = String::from_utf8(output.stdout)?; + Ok(Some(name.trim().to_string())) + } else { + Ok(None) + } +} + #[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] pub struct BlameEntry { pub sha: Oid, From 3d3a5ce2639019cdaa6fc2081a063e38cb503ad6 Mon Sep 17 00:00:00 2001 From: Harsh Narayan Jha Date: Mon, 25 Nov 2024 21:40:38 +0530 Subject: [PATCH 2/6] change for_path to accept author_display_replace to change author name on demand --- crates/git/src/blame.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/git/src/blame.rs b/crates/git/src/blame.rs index c3726e6f849d07..aa3793fb51618c 100644 --- a/crates/git/src/blame.rs +++ b/crates/git/src/blame.rs @@ -31,20 +31,19 @@ impl Blame { content: &Rope, remote_url: Option, provider_registry: Arc, + author_display_replace: Option<&str> ) -> Result { let output = run_git_blame(git_binary, working_directory, path, content)?; let mut entries = parse_git_blame(&output)?; entries.sort_unstable_by(|a, b| a.range.start.cmp(&b.range.start)); - let current_user = get_git_user_name(git_binary, working_directory)?; - - if let Some(username) = current_user { - for entry in &mut entries { - if let Some(ref author) = entry.author { - if author == &username { - entry.author = Some(format!("{} (You)", author)); - } - } + if let Some(replacement) = author_display_replace { + if let Some(username) = get_git_user_name(git_binary, working_directory)? { + let new_author = replacement.replace("{}", &username); + entries + .iter_mut() + .filter(|e| e.author.as_deref() == Some(&username)) + .for_each(|e| e.author = Some(new_author.clone())); } } From 4d4aec2420fe03a3e8daf575f160adc04c872e78 Mon Sep 17 00:00:00 2001 From: Harsh Narayan Jha Date: Mon, 25 Nov 2024 21:42:20 +0530 Subject: [PATCH 3/6] add new project_settings key to `InlineBlameSettings` called `author_display`. It defines how to display the author in git blame displays. add new enum `GitAuthorDisplaySetting` with values `Author` (default), `You`, `AuthorYou` Author -> Simply the default behaviour, e.g. `Linus Torvalds` You -> Shows `You` inplace of author name on your machine. e.g. `You` AuthorYou -> Both e.g. `Linus Torvalds (You)` currently there is one issue. updating the setting doesn't reflect rendered blames. need to toggle inline blames to take effect. --- crates/git/src/repository.rs | 7 ++++--- crates/project/src/buffer_store.rs | 18 +++++++++++++++++- crates/project/src/project_settings.rs | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/crates/git/src/repository.rs b/crates/git/src/repository.rs index 78f6ece508b937..4557d92d46ef30 100644 --- a/crates/git/src/repository.rs +++ b/crates/git/src/repository.rs @@ -44,7 +44,7 @@ pub trait GitRepository: Send + Sync { fn create_branch(&self, _: &str) -> Result<()>; fn branch_exits(&self, _: &str) -> Result; - fn blame(&self, path: &Path, content: Rope) -> Result; + fn blame(&self, path: &Path, content: Rope, author_display_replace: Option<&str>) -> Result; fn path(&self) -> PathBuf; } @@ -204,7 +204,7 @@ impl GitRepository for RealGitRepository { Ok(()) } - fn blame(&self, path: &Path, content: Rope) -> Result { + fn blame(&self, path: &Path, content: Rope, author_display_replace: Option<&str>) -> Result { let working_directory = self .repository .lock() @@ -222,6 +222,7 @@ impl GitRepository for RealGitRepository { &content, remote_url, self.hosting_provider_registry.clone(), + author_display_replace, ) } } @@ -349,7 +350,7 @@ impl GitRepository for FakeGitRepository { Ok(()) } - fn blame(&self, path: &Path, _content: Rope) -> Result { + fn blame(&self, path: &Path, _content: Rope, _author_replace_display: Option<&str>) -> Result { let state = self.state.lock(); state .blames diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index eb56680fb36f28..e04ba1e6c1b5c3 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -1,5 +1,6 @@ use crate::{ search::SearchQuery, + ProjectSettings, project_settings::GitAuthorDisplaySetting, worktree_store::{WorktreeStore, WorktreeStoreEvent}, Item, ProjectPath, }; @@ -23,6 +24,7 @@ use language::{ Buffer, BufferEvent, Capability, DiskState, File as _, Language, Operation, }; use rpc::{proto, AnyProtoClient, ErrorExt as _, TypedEnvelope}; +use settings::Settings; use smol::channel::Receiver; use std::{io, ops::Range, path::Path, str::FromStr as _, sync::Arc, time::Instant}; use text::BufferId; @@ -1124,11 +1126,25 @@ impl BufferStore { anyhow::Ok(Some((repo, relative_path, content))) }); + let author_display_setting = ProjectSettings::get_global(cx) + .git + .inline_blame + .unwrap_or_default() + .author_display + .unwrap_or_default(); + cx.background_executor().spawn(async move { let Some((repo, relative_path, content)) = blame_params? else { return Ok(None); }; - repo.blame(&relative_path, content) + + let author_display_replace = match author_display_setting { + GitAuthorDisplaySetting::Author => None, + GitAuthorDisplaySetting::You => Some("You"), + GitAuthorDisplaySetting::AuthorYou => Some("{} (You)"), + }; + + repo.blame(&relative_path, content, author_display_replace) .with_context(|| format!("Failed to blame {:?}", relative_path.0)) .map(Some) }) diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index bd0d7cc884f95e..f5579ad9016941 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -156,6 +156,22 @@ pub struct InlineBlameSettings { /// Default: false #[serde(default = "false_value")] pub show_commit_summary: bool, + /// Author display format for git blame. + /// + /// Default: author + pub author_display: Option, +} + +#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum GitAuthorDisplaySetting { + /// Only Author name. + #[default] + Author, + /// You + You, + /// Author (You) + AuthorYou, } const fn true_value() -> bool { From 4768e98f4c0b3343dc45f1bf1088907b27ca6993 Mon Sep 17 00:00:00 2001 From: Harsh Narayan Jha Date: Mon, 25 Nov 2024 21:50:14 +0530 Subject: [PATCH 4/6] fix: failing tests --- crates/collab/src/tests/editor_tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/collab/src/tests/editor_tests.rs b/crates/collab/src/tests/editor_tests.rs index beb1ef61ef9886..ef15a27c6a5cd5 100644 --- a/crates/collab/src/tests/editor_tests.rs +++ b/crates/collab/src/tests/editor_tests.rs @@ -1979,6 +1979,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA delay_ms: None, min_column: None, show_commit_summary: false, + author_display: None, }); cx_a.update(|cx| { SettingsStore::update_global(cx, |store, cx| { From 44a45039884b5ced3d9725792c733eca0e0c8977 Mon Sep 17 00:00:00 2001 From: Harsh Narayan Jha Date: Mon, 25 Nov 2024 22:00:23 +0530 Subject: [PATCH 5/6] chore: cargo fmt --- crates/git/src/blame.rs | 2 +- crates/git/src/repository.rs | 21 ++++++++++++++++++--- crates/project/src/buffer_store.rs | 4 ++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/crates/git/src/blame.rs b/crates/git/src/blame.rs index aa3793fb51618c..0f11a7e51f65ea 100644 --- a/crates/git/src/blame.rs +++ b/crates/git/src/blame.rs @@ -31,7 +31,7 @@ impl Blame { content: &Rope, remote_url: Option, provider_registry: Arc, - author_display_replace: Option<&str> + author_display_replace: Option<&str>, ) -> Result { let output = run_git_blame(git_binary, working_directory, path, content)?; let mut entries = parse_git_blame(&output)?; diff --git a/crates/git/src/repository.rs b/crates/git/src/repository.rs index 4557d92d46ef30..6d1d3bc59c9c87 100644 --- a/crates/git/src/repository.rs +++ b/crates/git/src/repository.rs @@ -44,7 +44,12 @@ pub trait GitRepository: Send + Sync { fn create_branch(&self, _: &str) -> Result<()>; fn branch_exits(&self, _: &str) -> Result; - fn blame(&self, path: &Path, content: Rope, author_display_replace: Option<&str>) -> Result; + fn blame( + &self, + path: &Path, + content: Rope, + author_display_replace: Option<&str>, + ) -> Result; fn path(&self) -> PathBuf; } @@ -204,7 +209,12 @@ impl GitRepository for RealGitRepository { Ok(()) } - fn blame(&self, path: &Path, content: Rope, author_display_replace: Option<&str>) -> Result { + fn blame( + &self, + path: &Path, + content: Rope, + author_display_replace: Option<&str>, + ) -> Result { let working_directory = self .repository .lock() @@ -350,7 +360,12 @@ impl GitRepository for FakeGitRepository { Ok(()) } - fn blame(&self, path: &Path, _content: Rope, _author_replace_display: Option<&str>) -> Result { + fn blame( + &self, + path: &Path, + _content: Rope, + _author_replace_display: Option<&str>, + ) -> Result { let state = self.state.lock(); state .blames diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index e04ba1e6c1b5c3..23bb90a4d91765 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -1,8 +1,8 @@ use crate::{ + project_settings::GitAuthorDisplaySetting, search::SearchQuery, - ProjectSettings, project_settings::GitAuthorDisplaySetting, worktree_store::{WorktreeStore, WorktreeStoreEvent}, - Item, ProjectPath, + Item, ProjectPath, ProjectSettings, }; use ::git::{parse_git_remote_url, BuildPermalinkParams, GitHostingProviderRegistry}; use anyhow::{anyhow, Context as _, Result}; From 964aa2421c894ed4f14c5267bdd718b79c358fb8 Mon Sep 17 00:00:00 2001 From: Harsh Narayan Jha Date: Mon, 2 Dec 2024 15:51:44 +0530 Subject: [PATCH 6/6] chore: cargo fmt --- crates/project/src/buffer_store.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index dff1cb05645653..2100b0e6e17b57 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -2,7 +2,7 @@ use crate::{ project_settings::GitAuthorDisplaySetting, search::SearchQuery, worktree_store::{WorktreeStore, WorktreeStoreEvent}, - Item, ProjectItem as _,ProjectPath, ProjectSettings, + ProjectItem as _, ProjectPath, ProjectSettings, }; use ::git::{parse_git_remote_url, BuildPermalinkParams, GitHostingProviderRegistry}; use anyhow::{anyhow, Context as _, Result};