Skip to content

Commit 1c1d69b

Browse files
committed
Add support for github enterprise and bitbucket. Fix ozanmakes#20
1 parent 9742a51 commit 1c1d69b

File tree

2 files changed

+107
-26
lines changed

2 files changed

+107
-26
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
github-browse-file
22
==================
33

4-
View the file you're editing in Emacs on GitHub.
4+
View the file you're editing in Emacs on GitHub or Bitbucket depending on the value of `remote.origin.url`.
55

66
### Installation:
77

@@ -18,6 +18,18 @@ Call `github-browse-file` (for the git blob) or `github-browse-file-blame`
1818

1919
`github-browse-commit` can be used to link to the current commit.
2020

21+
#### Enterprise support
22+
23+
If you use Github Enterprise or Bitbucket Server, add your domain to `github-browse-file-domains` via `customize` or use something like in your init file:
24+
25+
(add-to-list 'github-browse-file-domains '("git.dayjob.com" :type github))
26+
27+
For Bitbucket you would do:
28+
29+
(add-to-list 'github-browse-file-domains '("git.dayjob.com" :type bitbucket))
30+
31+
**Note:** This assumes that your hosted instance is listening on https.
32+
2133
### Contributors
2234
* [Charles Comstock](https://github.com/dgtized)
2335
* [Justin Talbott](https://github.com/waymondo)

github-browse-file.el

Lines changed: 94 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,40 @@
5050
:group 'github-browse-file
5151
:type 'boolean)
5252

53+
(defcustom github-browse-file-domains `(("github.com"
54+
:type github)
55+
("bitbucket.org"
56+
:type bitbucket))
57+
"Domains to match against and their repo types from `github-browse-file--repo-types'."
58+
:group 'github-browse-file
59+
:type '(alist :key-type string
60+
:value-type (plist :key-type (const :type)
61+
:value-type (choice (const bitbucket)
62+
(const github)))
63+
))
64+
65+
5366
(defcustom github-browse-file-show-line-at-point nil
5467
"If non-nil, link to the current line or active region"
5568
:group 'github-browse-file
5669
:type 'boolean)
5770

71+
(defvar github-browse-file--repo-types '((github
72+
:commit-dir "commit"
73+
:src-dir "blob"
74+
:blame-dir "blame"
75+
:tree-dir "tree"
76+
:anchor github-browse-file--format-anchors-github
77+
)
78+
(bitbucket
79+
:commit-dir "commits"
80+
:src-dir "src"
81+
:blame-dir "annotate"
82+
:tree-dir "src"
83+
:anchor github-browse-file--format-anchors-bitbucket))
84+
"The different supported enterprise type repositories supported.
85+
Based on the type, it informs `github-browse-file--absolute-url' how to construct the URL.")
86+
5887
(defvar github-browse-file--view-blame nil
5988
"If non-nil, view \"blame\" instead of \"blob\".
6089
This should only ever be `let'-bound, not set outright.")
@@ -67,14 +96,55 @@ This should only ever be `let'-bound, not set outright.")
6796
'(magit-commit-mode magit-revision-mode magit-log-mode)
6897
"Non-file magit modes that should link to commits.")
6998

70-
(defun github-browse-file--relative-url ()
71-
"Return \"username/repo\" for current repository.
72-
73-
Error out if this isn't a GitHub repo."
74-
(let ((url (vc-git--run-command-string nil "config" "remote.origin.url")))
75-
(unless url (error "Not in a GitHub repo"))
76-
(when (and url (string-match "github.com:?/?\\(.*\\)" url))
77-
(replace-regexp-in-string "\\.git$" "" (match-string 1 url)))))
99+
(defun github-browse-file--format-anchors-github (&optional anchor)
100+
(cond
101+
((= 1 (length anchor))
102+
(format "L%d" (car anchor)))
103+
((= 2 (length anchor))
104+
(format "L%d-L%d" (car anchor) (car (cdr anchor))))
105+
(t "")))
106+
107+
(defun github-browse-file--format-anchors-bitbucket (&optional anchor)
108+
""
109+
(let ((file-name (file-name-nondirectory (buffer-file-name))))
110+
(cond
111+
((= 1 (length anchor))
112+
(format "%s-%d" file-name (car anchor)))
113+
((= 2 (length anchor))
114+
(format "%s-%d:%d" file-name (car anchor) (car (cdr anchor))))
115+
(t ""))
116+
)
117+
)
118+
119+
(defun github-browse-file--remote-regexp (domain)
120+
(eval
121+
`(rx bol (or ,(concat "git@" domain ":")
122+
(and (or "git" "ssh" "http" "https") "://"
123+
(* nonl) (? "@") ,domain "/"))
124+
(and (group (* nonl) "/" (* nonl))) (? ".git"))))
125+
126+
(defun github-browse-file--get-regexps ()
127+
"Return the plist keyed by regexp of repo information."
128+
(loop for (key . domain-plist) in github-browse-file-domains
129+
collect (cons (github-browse-file--remote-regexp key)
130+
(plist-put domain-plist :url (concat "https://" key)))))
131+
132+
(defun github-browse-file--absolute-url (directory current-rev relative-path anchor)
133+
"Return \"https://DOMAIN/username/repo/current-rev/relative-path#anchor\" for current file.
134+
135+
(let ((url (vc-git--run-command-string nil "config" "remote.origin.url"))
136+
Error out if this isn't a remote repo."
137+
(regexps (github-browse-file--get-regexps)))
138+
(unless url (error "Not in a remote repo"))
139+
(cl-loop for (regexp . domain-plist) in regexps
140+
if (and url (string-match regexp url))
141+
return (let ((repo-plist (cdr (assoc (plist-get domain-plist :type) github-browse-file--repo-types))))
142+
(concat (plist-get domain-plist :url) "/"
143+
(replace-regexp-in-string "\\.git$" "" (match-string 1 url)) "/"
144+
(plist-get repo-plist directory) "/"
145+
(when current-rev (concat current-rev "/"))
146+
relative-path
147+
(when anchor (concat "#" (funcall (plist-get repo-plist :anchor) anchor))))))))
78148

79149
(defun github-browse-file--repo-relative-path ()
80150
"Return the path to the current file relative to the repository root."
@@ -116,17 +186,14 @@ Otherwise, return the name of the current branch."
116186
(and rev (replace-regexp-in-string "\n" "" rev))))))
117187

118188
(defun github-browse-file--browse-url (&optional anchor)
119-
"Load http://github.com/user/repo/file#ANCHOR in a web browser and add it to
189+
"Load http://DOMAIN/user/repo/file#ANCHOR in a web browser and add it to
120190
the kill ring."
121-
(let ((url (concat "https://github.com/"
122-
(github-browse-file--relative-url) "/"
123-
(cond ((eq major-mode 'magit-status-mode) "tree")
124-
((member major-mode github-browse-file--magit-commit-link-modes) "commit")
125-
(github-browse-file--view-blame "blame")
126-
(t "blob")) "/"
127-
(github-browse-file--current-rev) "/"
128-
(github-browse-file--repo-relative-path)
129-
(when anchor (concat "#" anchor)))))
191+
(let* ((directory (cond ((eq major-mode 'magit-status-mode) :tree-dir)
192+
((member major-mode github-browse-file--magit-commit-link-modes) :commit-dir)
193+
(github-browse-file--view-blame :blame-dir)
194+
(t :src-dir)))
195+
(current-rev (github-browse-file--current-rev))
196+
(url (concat (github-browse-file--absolute-url directory current-rev (github-browse-file--repo-relative-path) anchor))))
130197
(github-browse--save-and-view url)))
131198

132199
(defun github-browse-file--anchor-lines ()
@@ -140,10 +207,15 @@ default to current line."
140207
(end (line-number-at-pos (region-end))))
141208
(when (eq (char-before (region-end)) ?\n) (cl-decf end))
142209
(if (>= start end)
143-
(format "L%d" start)
144-
(format "L%d-L%d" start end))))
210+
`(,start nil)
211+
;; (format "L%d" start)
212+
;; (format "L%d-L%d" start end)
213+
`(,start ,end)
214+
)))
145215
(github-browse-file-show-line-at-point
146-
(format "L%d" (line-number-at-pos (point))))))
216+
`(,(line-number-at-pos (point)))
217+
;; (format "L%d" (line-number-at-pos (point)))
218+
)))
147219

148220
(defun github-browse-file--guess-commit ()
149221
"Guess the current git commit.
@@ -194,10 +266,7 @@ region."
194266
"Show the GitHub page for the current commit."
195267
(interactive)
196268
(let* ((commit (github-browse-file--guess-commit))
197-
(url (concat "https://github.com/"
198-
(github-browse-file--relative-url)
199-
"/commit/"
200-
commit)))
269+
(url (github-browse-file--absolute-url :commit-dir commit nil nil)))
201270
(github-browse--save-and-view url)))
202271

203272
(provide 'github-browse-file)

0 commit comments

Comments
 (0)