1use url::Url;
2
3use git::{BuildCommitPermalinkParams, BuildPermalinkParams, GitHostingProvider, ParsedGitRemote};
4
5pub struct Gitlab;
6
7impl GitHostingProvider for Gitlab {
8 fn name(&self) -> String {
9 "GitLab".to_string()
10 }
11
12 fn base_url(&self) -> Url {
13 Url::parse("https://gitlab.com").unwrap()
14 }
15
16 fn supports_avatars(&self) -> bool {
17 false
18 }
19
20 fn format_line_number(&self, line: u32) -> String {
21 format!("L{line}")
22 }
23
24 fn format_line_numbers(&self, start_line: u32, end_line: u32) -> String {
25 format!("L{start_line}-{end_line}")
26 }
27
28 fn parse_remote_url<'a>(&self, url: &'a str) -> Option<ParsedGitRemote<'a>> {
29 if url.starts_with("git@gitlab.com:") || url.starts_with("https://gitlab.com/") {
30 let repo_with_owner = url
31 .trim_start_matches("git@gitlab.com:")
32 .trim_start_matches("https://gitlab.com/")
33 .trim_end_matches(".git");
34
35 let (owner, repo) = repo_with_owner.split_once('/')?;
36
37 return Some(ParsedGitRemote { owner, repo });
38 }
39
40 None
41 }
42
43 fn build_commit_permalink(
44 &self,
45 remote: &ParsedGitRemote,
46 params: BuildCommitPermalinkParams,
47 ) -> Url {
48 let BuildCommitPermalinkParams { sha } = params;
49 let ParsedGitRemote { owner, repo } = remote;
50
51 self.base_url()
52 .join(&format!("{owner}/{repo}/-/commit/{sha}"))
53 .unwrap()
54 }
55
56 fn build_permalink(&self, remote: ParsedGitRemote, params: BuildPermalinkParams) -> Url {
57 let ParsedGitRemote { owner, repo } = remote;
58 let BuildPermalinkParams {
59 sha,
60 path,
61 selection,
62 } = params;
63
64 let mut permalink = self
65 .base_url()
66 .join(&format!("{owner}/{repo}/-/blob/{sha}/{path}"))
67 .unwrap();
68 if path.ends_with(".md") {
69 permalink.set_query(Some("plain=1"));
70 }
71 permalink.set_fragment(
72 selection
73 .map(|selection| self.line_fragment(&selection))
74 .as_deref(),
75 );
76 permalink
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_build_gitlab_permalink_from_ssh_url() {
86 let remote = ParsedGitRemote {
87 owner: "zed-industries",
88 repo: "zed",
89 };
90 let permalink = Gitlab.build_permalink(
91 remote,
92 BuildPermalinkParams {
93 sha: "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7",
94 path: "crates/editor/src/git/permalink.rs",
95 selection: None,
96 },
97 );
98
99 let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7/crates/editor/src/git/permalink.rs";
100 assert_eq!(permalink.to_string(), expected_url.to_string())
101 }
102
103 #[test]
104 fn test_build_gitlab_permalink_from_ssh_url_single_line_selection() {
105 let remote = ParsedGitRemote {
106 owner: "zed-industries",
107 repo: "zed",
108 };
109 let permalink = Gitlab.build_permalink(
110 remote,
111 BuildPermalinkParams {
112 sha: "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7",
113 path: "crates/editor/src/git/permalink.rs",
114 selection: Some(6..6),
115 },
116 );
117
118 let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7/crates/editor/src/git/permalink.rs#L7";
119 assert_eq!(permalink.to_string(), expected_url.to_string())
120 }
121
122 #[test]
123 fn test_build_gitlab_permalink_from_ssh_url_multi_line_selection() {
124 let remote = ParsedGitRemote {
125 owner: "zed-industries",
126 repo: "zed",
127 };
128 let permalink = Gitlab.build_permalink(
129 remote,
130 BuildPermalinkParams {
131 sha: "e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7",
132 path: "crates/editor/src/git/permalink.rs",
133 selection: Some(23..47),
134 },
135 );
136
137 let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/e6ebe7974deb6bb6cc0e2595c8ec31f0c71084b7/crates/editor/src/git/permalink.rs#L24-48";
138 assert_eq!(permalink.to_string(), expected_url.to_string())
139 }
140
141 #[test]
142 fn test_build_gitlab_permalink_from_https_url() {
143 let remote = ParsedGitRemote {
144 owner: "zed-industries",
145 repo: "zed",
146 };
147 let permalink = Gitlab.build_permalink(
148 remote,
149 BuildPermalinkParams {
150 sha: "b2efec9824c45fcc90c9a7eb107a50d1772a60aa",
151 path: "crates/zed/src/main.rs",
152 selection: None,
153 },
154 );
155
156 let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/b2efec9824c45fcc90c9a7eb107a50d1772a60aa/crates/zed/src/main.rs";
157 assert_eq!(permalink.to_string(), expected_url.to_string())
158 }
159
160 #[test]
161 fn test_build_gitlab_permalink_from_https_url_single_line_selection() {
162 let remote = ParsedGitRemote {
163 owner: "zed-industries",
164 repo: "zed",
165 };
166 let permalink = Gitlab.build_permalink(
167 remote,
168 BuildPermalinkParams {
169 sha: "b2efec9824c45fcc90c9a7eb107a50d1772a60aa",
170 path: "crates/zed/src/main.rs",
171 selection: Some(6..6),
172 },
173 );
174
175 let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/b2efec9824c45fcc90c9a7eb107a50d1772a60aa/crates/zed/src/main.rs#L7";
176 assert_eq!(permalink.to_string(), expected_url.to_string())
177 }
178
179 #[test]
180 fn test_build_gitlab_permalink_from_https_url_multi_line_selection() {
181 let remote = ParsedGitRemote {
182 owner: "zed-industries",
183 repo: "zed",
184 };
185 let permalink = Gitlab.build_permalink(
186 remote,
187 BuildPermalinkParams {
188 sha: "b2efec9824c45fcc90c9a7eb107a50d1772a60aa",
189 path: "crates/zed/src/main.rs",
190 selection: Some(23..47),
191 },
192 );
193
194 let expected_url = "https://gitlab.com/zed-industries/zed/-/blob/b2efec9824c45fcc90c9a7eb107a50d1772a60aa/crates/zed/src/main.rs#L24-48";
195 assert_eq!(permalink.to_string(), expected_url.to_string())
196 }
197}