diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index b3adf64a943c646ea42c084665cee5a5ef04c8a1..2b6efc8100d179926eb95e532849ad16d3ef5058 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -8625,8 +8625,6 @@ impl Editor { } fn get_permalink_to_line(&mut self, cx: &mut ViewContext) -> Result { - use git::permalink::{build_permalink, BuildPermalinkParams}; - let project = self.project.clone().ok_or_else(|| anyhow!("no project"))?; let project = project.read(cx); @@ -8651,7 +8649,6 @@ impl Editor { .lock() .head_sha() .ok_or_else(|| anyhow!("failed to read HEAD SHA"))?; - let path = maybe!({ let buffer = self.buffer().read(cx).as_singleton()?; let file = buffer.read(cx).file().and_then(|f| f.as_local())?; @@ -8662,12 +8659,12 @@ impl Editor { let selections = self.selections.all::(cx); let selection = selections.iter().peekable().next(); - build_permalink(BuildPermalinkParams { - remote_url: &origin_url, - sha: &sha, - path: &path, - selection: selection.map(|selection| selection.range()), - }) + git::permalink::build_permalink( + &origin_url, + &sha, + &path, + selection.map(|selection| selection.range()), + ) } pub fn copy_permalink_to_line(&mut self, _: &CopyPermalinkToLine, cx: &mut ViewContext) { diff --git a/crates/editor/src/git/permalink.rs b/crates/editor/src/git/permalink.rs index 39edae0dce56cda2aa1a2f3bc4720b385e32da0f..9649fb5727f5502f5c9bcc3db7d0430a5f8ff990 100644 --- a/crates/editor/src/git/permalink.rs +++ b/crates/editor/src/git/permalink.rs @@ -8,6 +8,7 @@ enum GitHostingProvider { Github, Gitlab, Gitee, + BitbucketCloud, } impl GitHostingProvider { @@ -16,6 +17,7 @@ impl GitHostingProvider { Self::Github => "https://github.com", Self::Gitlab => "https://gitlab.com", Self::Gitee => "https://gitee.com", + Self::BitbucketCloud => "https://bitbucket.org", }; Url::parse(&base_url).unwrap() @@ -29,6 +31,7 @@ impl GitHostingProvider { match self { Self::Github | Self::Gitlab | Self::Gitee => format!("L{}", line), + Self::BitbucketCloud => format!("lines-{}", line), } } else { let start_line = selection.start.row + 1; @@ -36,28 +39,19 @@ impl GitHostingProvider { match self { Self::Github => format!("L{}-L{}", start_line, end_line), - Self::Gitlab => format!("L{}-{}", start_line, end_line), - Self::Gitee => format!("L{}-{}", start_line, end_line), + Self::Gitlab | Self::Gitee => format!("L{}-{}", start_line, end_line), + Self::BitbucketCloud => format!("lines-{}:{}", start_line, end_line), } } } } -pub struct BuildPermalinkParams<'a> { - pub remote_url: &'a str, - pub sha: &'a str, - pub path: &'a str, - pub selection: Option>, -} - -pub fn build_permalink(params: BuildPermalinkParams) -> Result { - let BuildPermalinkParams { - remote_url, - sha, - path, - selection, - } = params; - +pub fn build_permalink( + remote_url: &str, + sha: &str, + path: &str, + selection: Option>, +) -> Result { let ParsedGitRemote { provider, owner, @@ -69,6 +63,7 @@ pub fn build_permalink(params: BuildPermalinkParams) -> Result { GitHostingProvider::Github => format!("{owner}/{repo}/blob/{sha}/{path}"), GitHostingProvider::Gitlab => format!("{owner}/{repo}/-/blob/{sha}/{path}"), GitHostingProvider::Gitee => format!("{owner}/{repo}/blob/{sha}/{path}"), + GitHostingProvider::BitbucketCloud => format!("{owner}/{repo}/src/{sha}/{path}"), }; let line_fragment = selection.map(|selection| provider.line_fragment(&selection)); @@ -130,6 +125,20 @@ fn parse_git_remote_url(url: &str) -> Option { }); } + if url.contains("bitbucket.org") { + let (_, repo_with_owner) = url.trim_end_matches(".git").split_once("bitbucket.org")?; + let (owner, repo) = repo_with_owner + .trim_start_matches("/") + .trim_start_matches(":") + .split_once("/")?; + + return Some(ParsedGitRemote { + provider: GitHostingProvider::BitbucketCloud, + owner, + repo, + }); + } + None } @@ -139,12 +148,12 @@ mod tests { #[test] fn test_build_github_permalink_from_ssh_url() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "git@github.com:zed-industries/zed.git", - sha: "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", - path: "crates/editor/src/git/permalink.rs", - selection: None, - }) + let permalink = build_permalink( + "git@github.com:zed-industries/zed.git", + "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", + "crates/editor/src/git/permalink.rs", + None, + ) .unwrap(); let expected_url = "https://github.com/zed-industries/zed/blob/e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7/crates/editor/src/git/permalink.rs"; @@ -153,12 +162,12 @@ mod tests { #[test] fn test_build_github_permalink_from_ssh_url_single_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "git@github.com:zed-industries/zed.git", - sha: "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", - path: "crates/editor/src/git/permalink.rs", - selection: Some(Point::new(6, 1)..Point::new(6, 10)), - }) + let permalink = build_permalink( + "git@github.com:zed-industries/zed.git", + "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", + "crates/editor/src/git/permalink.rs", + Some(Point::new(6, 1)..Point::new(6, 10)), + ) .unwrap(); let expected_url = "https://github.com/zed-industries/zed/blob/e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7/crates/editor/src/git/permalink.rs#L7"; @@ -167,12 +176,12 @@ mod tests { #[test] fn test_build_github_permalink_from_ssh_url_multi_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "git@github.com:zed-industries/zed.git", - sha: "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", - path: "crates/editor/src/git/permalink.rs", - selection: Some(Point::new(23, 1)..Point::new(47, 10)), - }) + let permalink = build_permalink( + "git@github.com:zed-industries/zed.git", + "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", + "crates/editor/src/git/permalink.rs", + Some(Point::new(23, 1)..Point::new(47, 10)), + ) .unwrap(); let expected_url = "https://github.com/zed-industries/zed/blob/e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7/crates/editor/src/git/permalink.rs#L24-L48"; @@ -181,12 +190,12 @@ mod tests { #[test] fn test_build_github_permalink_from_https_url() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "https://github.com/zed-industries/zed.git", - sha: "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", - path: "crates/zed/src/main.rs", - selection: None, - }) + let permalink = build_permalink( + "https://github.com/zed-industries/zed.git", + "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", + "crates/zed/src/main.rs", + None, + ) .unwrap(); let expected_url = "https://github.com/zed-industries/zed/blob/b2efec9824c45fcc90c9a7eb107a50d1772a60aa/crates/zed/src/main.rs"; @@ -195,12 +204,12 @@ mod tests { #[test] fn test_build_github_permalink_from_https_url_single_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "https://github.com/zed-industries/zed.git", - sha: "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", - path: "crates/zed/src/main.rs", - selection: Some(Point::new(6, 1)..Point::new(6, 10)), - }) + let permalink = build_permalink( + "https://github.com/zed-industries/zed.git", + "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", + "crates/zed/src/main.rs", + Some(Point::new(6, 1)..Point::new(6, 10)), + ) .unwrap(); let expected_url = "https://github.com/zed-industries/zed/blob/b2efec9824c45fcc90c9a7eb107a50d1772a60aa/crates/zed/src/main.rs#L7"; @@ -209,12 +218,12 @@ mod tests { #[test] fn test_build_github_permalink_from_https_url_multi_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "https://github.com/zed-industries/zed.git", - sha: "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", - path: "crates/zed/src/main.rs", - selection: Some(Point::new(23, 1)..Point::new(47, 10)), - }) + let permalink = build_permalink( + "https://github.com/zed-industries/zed.git", + "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", + "crates/zed/src/main.rs", + Some(Point::new(23, 1)..Point::new(47, 10)), + ) .unwrap(); let expected_url = "https://github.com/zed-industries/zed/blob/b2efec9824c45fcc90c9a7eb107a50d1772a60aa/crates/zed/src/main.rs#L24-L48"; @@ -223,12 +232,12 @@ mod tests { #[test] fn test_build_gitlab_permalink_from_ssh_url() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "git@gitlab.com:zed-industries/zed.git", - sha: "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", - path: "crates/editor/src/git/permalink.rs", - selection: None, - }) + let permalink = build_permalink( + "git@gitlab.com:zed-industries/zed.git", + "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", + "crates/editor/src/git/permalink.rs", + None, + ) .unwrap(); let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7/crates/editor/src/git/permalink.rs"; @@ -237,12 +246,12 @@ mod tests { #[test] fn test_build_gitlab_permalink_from_ssh_url_single_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "git@gitlab.com:zed-industries/zed.git", - sha: "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", - path: "crates/editor/src/git/permalink.rs", - selection: Some(Point::new(6, 1)..Point::new(6, 10)), - }) + let permalink = build_permalink( + "git@gitlab.com:zed-industries/zed.git", + "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", + "crates/editor/src/git/permalink.rs", + Some(Point::new(6, 1)..Point::new(6, 10)), + ) .unwrap(); let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7/crates/editor/src/git/permalink.rs#L7"; @@ -251,12 +260,12 @@ mod tests { #[test] fn test_build_gitlab_permalink_from_ssh_url_multi_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "git@gitlab.com:zed-industries/zed.git", - sha: "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", - path: "crates/editor/src/git/permalink.rs", - selection: Some(Point::new(23, 1)..Point::new(47, 10)), - }) + let permalink = build_permalink( + "git@gitlab.com:zed-industries/zed.git", + "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7", + "crates/editor/src/git/permalink.rs", + Some(Point::new(23, 1)..Point::new(47, 10)), + ) .unwrap(); let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7/crates/editor/src/git/permalink.rs#L24-48"; @@ -265,12 +274,12 @@ mod tests { #[test] fn test_build_gitlab_permalink_from_https_url() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "https://gitlab.com/zed-industries/zed.git", - sha: "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", - path: "crates/zed/src/main.rs", - selection: None, - }) + let permalink = build_permalink( + "https://gitlab.com/zed-industries/zed.git", + "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", + "crates/zed/src/main.rs", + None, + ) .unwrap(); let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/b2efec9824c45fcc90c9a7eb107a50d1772a60aa/crates/zed/src/main.rs"; @@ -279,12 +288,12 @@ mod tests { #[test] fn test_build_gitlab_permalink_from_https_url_single_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "https://gitlab.com/zed-industries/zed.git", - sha: "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", - path: "crates/zed/src/main.rs", - selection: Some(Point::new(6, 1)..Point::new(6, 10)), - }) + let permalink = build_permalink( + "https://gitlab.com/zed-industries/zed.git", + "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", + "crates/zed/src/main.rs", + Some(Point::new(6, 1)..Point::new(6, 10)), + ) .unwrap(); let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/b2efec9824c45fcc90c9a7eb107a50d1772a60aa/crates/zed/src/main.rs#L7"; @@ -293,12 +302,12 @@ mod tests { #[test] fn test_build_gitlab_permalink_from_https_url_multi_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "https://gitlab.com/zed-industries/zed.git", - sha: "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", - path: "crates/zed/src/main.rs", - selection: Some(Point::new(23, 1)..Point::new(47, 10)), - }) + let permalink = build_permalink( + "https://gitlab.com/zed-industries/zed.git", + "b2efec9824c45fcc90c9a7eb107a50d1772a60aa", + "crates/zed/src/main.rs", + Some(Point::new(23, 1)..Point::new(47, 10)), + ) .unwrap(); let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/b2efec9824c45fcc90c9a7eb107a50d1772a60aa/crates/zed/src/main.rs#L24-48"; @@ -307,12 +316,12 @@ mod tests { #[test] fn test_build_gitee_permalink_from_ssh_url() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "git@gitee.com:libkitten/zed.git", - sha: "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", - path: "crates/editor/src/git/permalink.rs", - selection: None, - }) + let permalink = build_permalink( + "git@gitee.com:libkitten/zed.git", + "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", + "crates/editor/src/git/permalink.rs", + None, + ) .unwrap(); let expected_url = "https://gitee.com/libkitten/zed/blob/e5fe811d7ad0fc26934edd76f891d20bdc3bb194/crates/editor/src/git/permalink.rs"; @@ -321,12 +330,12 @@ mod tests { #[test] fn test_build_gitee_permalink_from_ssh_url_single_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "git@gitee.com:libkitten/zed.git", - sha: "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", - path: "crates/editor/src/git/permalink.rs", - selection: Some(Point::new(6, 1)..Point::new(6, 10)), - }) + let permalink = build_permalink( + "git@gitee.com:libkitten/zed.git", + "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", + "crates/editor/src/git/permalink.rs", + Some(Point::new(6, 1)..Point::new(6, 10)), + ) .unwrap(); let expected_url = "https://gitee.com/libkitten/zed/blob/e5fe811d7ad0fc26934edd76f891d20bdc3bb194/crates/editor/src/git/permalink.rs#L7"; @@ -335,12 +344,12 @@ mod tests { #[test] fn test_build_gitee_permalink_from_ssh_url_multi_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "git@gitee.com:libkitten/zed.git", - sha: "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", - path: "crates/editor/src/git/permalink.rs", - selection: Some(Point::new(23, 1)..Point::new(47, 10)), - }) + let permalink = build_permalink( + "git@gitee.com:libkitten/zed.git", + "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", + "crates/editor/src/git/permalink.rs", + Some(Point::new(23, 1)..Point::new(47, 10)), + ) .unwrap(); let expected_url = "https://gitee.com/libkitten/zed/blob/e5fe811d7ad0fc26934edd76f891d20bdc3bb194/crates/editor/src/git/permalink.rs#L24-48"; @@ -349,12 +358,12 @@ mod tests { #[test] fn test_build_gitee_permalink_from_https_url() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "https://gitee.com/libkitten/zed.git", - sha: "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", - path: "crates/zed/src/main.rs", - selection: None, - }) + let permalink = build_permalink( + "https://gitee.com/libkitten/zed.git", + "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", + "crates/zed/src/main.rs", + None, + ) .unwrap(); let expected_url = "https://gitee.com/libkitten/zed/blob/e5fe811d7ad0fc26934edd76f891d20bdc3bb194/crates/zed/src/main.rs"; @@ -363,12 +372,12 @@ mod tests { #[test] fn test_build_gitee_permalink_from_https_url_single_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "https://gitee.com/libkitten/zed.git", - sha: "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", - path: "crates/zed/src/main.rs", - selection: Some(Point::new(6, 1)..Point::new(6, 10)), - }) + let permalink = build_permalink( + "https://gitee.com/libkitten/zed.git", + "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", + "crates/zed/src/main.rs", + Some(Point::new(6, 1)..Point::new(6, 10)), + ) .unwrap(); let expected_url = "https://gitee.com/libkitten/zed/blob/e5fe811d7ad0fc26934edd76f891d20bdc3bb194/crates/zed/src/main.rs#L7"; @@ -377,14 +386,94 @@ mod tests { #[test] fn test_build_gitee_permalink_from_https_url_multi_line_selection() { - let permalink = build_permalink(BuildPermalinkParams { - remote_url: "https://gitee.com/libkitten/zed.git", - sha: "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", - path: "crates/zed/src/main.rs", - selection: Some(Point::new(23, 1)..Point::new(47, 10)), - }) + let permalink = build_permalink( + "https://gitee.com/libkitten/zed.git", + "e5fe811d7ad0fc26934edd76f891d20bdc3bb194", + "crates/zed/src/main.rs", + Some(Point::new(23, 1)..Point::new(47, 10)), + ) .unwrap(); let expected_url = "https://gitee.com/libkitten/zed/blob/e5fe811d7ad0fc26934edd76f891d20bdc3bb194/crates/zed/src/main.rs#L24-48"; assert_eq!(permalink.to_string(), expected_url.to_string()) } + + #[test] + fn test_parse_git_remote_url_bitbucket_https_with_username() { + let url = "https://thorstenballzed@bitbucket.org/thorstenzed/testingrepo.git"; + let parsed = parse_git_remote_url(url).unwrap(); + assert!(matches!( + parsed.provider, + GitHostingProvider::BitbucketCloud + )); + assert_eq!(parsed.owner, "thorstenzed"); + assert_eq!(parsed.repo, "testingrepo"); + } + + #[test] + fn test_parse_git_remote_url_bitbucket_https_without_username() { + let url = "https://bitbucket.org/thorstenzed/testingrepo.git"; + let parsed = parse_git_remote_url(url).unwrap(); + assert!(matches!( + parsed.provider, + GitHostingProvider::BitbucketCloud + )); + assert_eq!(parsed.owner, "thorstenzed"); + assert_eq!(parsed.repo, "testingrepo"); + } + + #[test] + fn test_parse_git_remote_url_bitbucket_git() { + let url = "git@bitbucket.org:thorstenzed/testingrepo.git"; + let parsed = parse_git_remote_url(url).unwrap(); + assert!(matches!( + parsed.provider, + GitHostingProvider::BitbucketCloud + )); + assert_eq!(parsed.owner, "thorstenzed"); + assert_eq!(parsed.repo, "testingrepo"); + } + + #[test] + fn test_build_bitbucket_permalink_from_ssh_url() { + let permalink = build_permalink( + "git@bitbucket.org:thorstenzed/testingrepo.git", + "f00b4r", + "main.rs", + None, + ) + .unwrap(); + + let expected_url = "https://bitbucket.org/thorstenzed/testingrepo/src/f00b4r/main.rs"; + assert_eq!(permalink.to_string(), expected_url.to_string()) + } + + #[test] + fn test_build_bitbucket_permalink_from_ssh_url_single_line_selection() { + let permalink = build_permalink( + "git@bitbucket.org:thorstenzed/testingrepo.git", + "f00b4r", + "main.rs", + Some(Point::new(6, 1)..Point::new(6, 10)), + ) + .unwrap(); + + let expected_url = + "https://bitbucket.org/thorstenzed/testingrepo/src/f00b4r/main.rs#lines-7"; + assert_eq!(permalink.to_string(), expected_url.to_string()) + } + + #[test] + fn test_build_bitbucket_permalink_from_ssh_url_multi_line_selection() { + let permalink = build_permalink( + "git@bitbucket.org:thorstenzed/testingrepo.git", + "f00b4r", + "main.rs", + Some(Point::new(23, 1)..Point::new(47, 10)), + ) + .unwrap(); + + let expected_url = + "https://bitbucket.org/thorstenzed/testingrepo/src/f00b4r/main.rs#lines-24:48"; + assert_eq!(permalink.to_string(), expected_url.to_string()) + } }