From 0ea0a6e4360b8d5c0f4448e24793b2b93974598d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Mercier?= Date: Fri, 6 Mar 2026 16:19:02 -0500 Subject: [PATCH 1/2] feat(hyperlinks): add Bitbucket support for commit hyperlinks Add Bitbucket as a supported hosting provider when formatting commits as hyperlinks with --hyperlinks. Supports both HTTPS and SSH remote URL formats, and formats commit URLs as: https://bitbucket.org/{user}/{repo}/commits/{hash} --- README.md | 2 +- src/git_config/remote.rs | 64 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 83c0244e1..65f6b4f95 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Delta has many features and is very customizable; please see `delta -h` (short h - Line numbering - `n` and `N` keybindings to move between files in large diffs, and between diffs in `log -p` views (`--navigate`) - Improved merge conflict display -- Improved `git blame` display (syntax highlighting; `--hyperlinks` formats commits as links to hosting provider etc. Supported hosting providers are: GitHub, GitLab, SourceHut, Codeberg) +- Improved `git blame` display (syntax highlighting; `--hyperlinks` formats commits as links to hosting provider etc. Supported hosting providers are: GitHub, GitLab, SourceHut, Codeberg, Bitbucket) - Syntax-highlights grep output from `rg`, `git grep`, `grep`, etc - Support for Git's `--color-moved` feature. - Code can be copied directly from the diff (`-/+` markers are removed by default). diff --git a/src/git_config/remote.rs b/src/git_config/remote.rs index 6737a5031..ea11aab47 100644 --- a/src/git_config/remote.rs +++ b/src/git_config/remote.rs @@ -12,6 +12,7 @@ pub enum GitRemoteRepo { GitLab { slug: String }, SourceHut { slug: String }, Codeberg { slug: String }, + Bitbucket { slug: String }, } impl GitRemoteRepo { @@ -29,6 +30,9 @@ impl GitRemoteRepo { Self::Codeberg { slug } => { format!("https://codeberg.org/{slug}/commit/{commit}") } + Self::Bitbucket { slug } => { + format!("https://bitbucket.org/{slug}/commits/{commit}") + } } } @@ -97,6 +101,20 @@ lazy_static! { " ) .unwrap(); + static ref BITBUCKET_REMOTE_URL: Regex = Regex::new( + r"(?x) + ^ + (?:https://|git@)? # Support both HTTPS and SSH URLs, SSH URLs optionally omitting the git@ + bitbucket\.org + [:/] # This separator differs between SSH and HTTPS URLs + ([^/]+) # Capture the user/org name + / + (.+?) # Capture the repo name (lazy to avoid consuming '.git' if present) + (?:\.git)? # Non-capturing group to consume '.git' if present + $ + " + ) + .unwrap(); } impl FromStr for GitRemoteRepo { @@ -135,8 +153,16 @@ impl FromStr for GitRemoteRepo { repo = caps.get(2).unwrap().as_str() ), }) + } else if let Some(caps) = BITBUCKET_REMOTE_URL.captures(s) { + Ok(Self::Bitbucket { + slug: format!( + "{user}/{repo}", + user = caps.get(1).unwrap().as_str(), + repo = caps.get(2).unwrap().as_str() + ), + }) } else { - Err(anyhow!("Not a GitHub, GitLab, SourceHut or Codeberg repo.")) + Err(anyhow!("Not a GitHub, GitLab, SourceHut, Codeberg or Bitbucket repo.")) } } } @@ -288,4 +314,38 @@ mod tests { format!("https://codeberg.org/dnkl/foot/commit/{commit_hash}") ) } -} + + #[test] + fn test_parse_bitbucket_urls() { + let urls = &[ + "https://bitbucket.org/someuser/somerepo.git", + "https://bitbucket.org/someuser/somerepo", + "git@bitbucket.org:someuser/somerepo.git", + "git@bitbucket.org:someuser/somerepo", + "bitbucket.org:someuser/somerepo.git", + "bitbucket.org:someuser/somerepo", + ]; + for url in urls { + let parsed = GitRemoteRepo::from_str(url); + assert!(parsed.is_ok()); + assert_eq!( + parsed.unwrap(), + GitRemoteRepo::Bitbucket { + slug: "someuser/somerepo".to_string() + } + ); + } + } + + #[test] + fn test_format_bitbucket_commit_link() { + let repo = GitRemoteRepo::Bitbucket { + slug: "someuser/somerepo".to_string(), + }; + let commit_hash = "1c072856ebf12419378c5098ad543c497197c6da"; + assert_eq!( + repo.format_commit_url(commit_hash), + format!("https://bitbucket.org/someuser/somerepo/commits/{commit_hash}") + ) + } +} \ No newline at end of file From 4a92da5545b916bc19cdbe2972516eb8b2a2a73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Mercier?= Date: Fri, 6 Mar 2026 20:56:09 -0500 Subject: [PATCH 2/2] style(git_config): fix formatting in remote.rs Reformat long anyhow! macro call to multi-line style and add missing newline at end of file. --- src/git_config/remote.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/git_config/remote.rs b/src/git_config/remote.rs index ea11aab47..5269728bf 100644 --- a/src/git_config/remote.rs +++ b/src/git_config/remote.rs @@ -162,7 +162,9 @@ impl FromStr for GitRemoteRepo { ), }) } else { - Err(anyhow!("Not a GitHub, GitLab, SourceHut, Codeberg or Bitbucket repo.")) + Err(anyhow!( + "Not a GitHub, GitLab, SourceHut, Codeberg or Bitbucket repo." + )) } } } @@ -348,4 +350,4 @@ mod tests { format!("https://bitbucket.org/someuser/somerepo/commits/{commit_hash}") ) } -} \ No newline at end of file +}