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\" .
6089This 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
120190the 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