Skip to content

Commit 13dd90e

Browse files
committed
Support visiting blobs using a browser
1 parent 0c81b44 commit 13dd90e

File tree

11 files changed

+136
-10
lines changed

11 files changed

+136
-10
lines changed

docs/forge.org

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,7 @@ argument, i.e., ~C-u RET~.
869869
- Key: o [on repository in repository list] (forge-browse-this-repository) ::
870870

871871
These commands visit the topic, issue(s), pull-request(s), post,
872-
branch, commit, remote or repository at point in a browser.
872+
branch, commit, remote, repository or blob at point in a browser.
873873

874874
- Command: forge-browse-commit ::
875875
- Command: forge-browse-branch ::
@@ -884,6 +884,22 @@ argument, i.e., ~C-u RET~.
884884
These commands read a topic, issue(s), pull-request(s), branch,
885885
commit, remote or repository, and open it in a browser.
886886

887+
- Command: forge-browse-commit ::
888+
889+
This command visit a blob in a browser.
890+
891+
When invoked from a blob- or file-visiting buffer, visit that blob
892+
without prompting. If the region is active, try to jump to the marked
893+
line or lines, and highlight them in the browser. To what extend that
894+
is possible depends on the forge. When the region is not active just
895+
visit the blob, without trying to jump to the current line. When
896+
jumping to a line, always use a commit hash as part of the URL. From
897+
a file in the worktree with no active region, instead use the branch
898+
name as part of the URL, unless a prefix argument is used.
899+
900+
When invoked from any other buffer, prompt the user for a branch or
901+
commit, and for a file.
902+
887903
* Creating Topics and Posts
888904

889905
We call both issues and pull-requests "topics". The contributions to

docs/forge.texi

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ separate buffer.
996996
@findex forge-browse-this-topic
997997
@findex forge-browse-this-repository
998998
These commands visit the topic, issue(s), pull-request(s), post,
999-
branch, commit, remote or repository at point in a browser.
999+
branch, commit, remote, repository or blob at point in a browser.
10001000
@end table
10011001

10021002
@deffn Command forge-browse-commit
@@ -1028,6 +1028,22 @@ These commands read a topic, issue(s), pull-request(s), branch,
10281028
commit, remote or repository, and open it in a browser.
10291029
@end table
10301030

1031+
@deffn Command forge-browse-commit
1032+
This command visit a blob in a browser.
1033+
1034+
When invoked from a blob- or file-visiting buffer, visit that blob
1035+
without prompting. If the region is active, try to jump to the marked
1036+
line or lines, and highlight them in the browser. To what extend that
1037+
is possible depends on the forge. When the region is not active just
1038+
visit the blob, without trying to jump to the current line. When
1039+
jumping to a line, always use a commit hash as part of the URL@. From
1040+
a file in the worktree with no active region, instead use the branch
1041+
name as part of the URL, unless a prefix argument is used.
1042+
1043+
When invoked from any other buffer, prompt the user for a branch or
1044+
commit, and for a file.
1045+
@end deffn
1046+
10311047
@node Creating Topics and Posts
10321048
@chapter Creating Topics and Posts
10331049

lisp/forge-bitbucket.el

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
(commit-url-format :initform "https://%h/%o/%n/commits/%r")
3939
(branch-url-format :initform "https://%h/%o/%n/branch/%r")
4040
(remote-url-format :initform "https://%h/%o/%n/src")
41+
(blob-url-format :initform "https://%h/%o/%n/src/%r/%f")
4142
(create-issue-url-format :initform "https://%h/%o/%n/issues/new")
4243
(create-pullreq-url-format :initform "https://%h/%o/%n/pull-requests/new")))
4344

lisp/forge-commands.el

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,24 @@ argument also offer closed pull-requests."
293293
(interactive (list (forge-read-repository "Browse repository")))
294294
(browse-url (forge-get-url repository)))
295295

296+
;;;###autoload
297+
(defun forge-browse-blob (commit file &optional line end force-hash)
298+
"Visit a blob using a browser.
299+
300+
When invoked from a blob- or file-visiting buffer, visit that blob
301+
without prompting. If the region is active, try to jump to the marked
302+
line or lines, and highlight them in the browser. To what extend that
303+
is possible depends on the forge. When the region is not active just
304+
visit the blob, without trying to jump to the current line. When
305+
jumping to a line, always use a commit hash as part of the URL. From
306+
a file in the worktree with no active region, instead use the branch
307+
name as part of the URL, unless a prefix argument is used.
308+
309+
When invoked from any other buffer, prompt the user for a branch or
310+
commit, and for a file."
311+
(interactive (forge--browse-blob-args))
312+
(browse-url (forge-get-url :blob commit file line end force-hash)))
313+
296314
;;;###autoload(autoload 'forge-browse-this-topic "forge-commands" nil t)
297315
(transient-define-suffix forge-browse-this-topic ()
298316
"Visit the topic at point using a browser."
@@ -308,7 +326,7 @@ argument also offer closed pull-requests."
308326

309327
;;;###autoload
310328
(defun forge-copy-url-at-point-as-kill ()
311-
"Copy the url of the thing at point."
329+
"Copy the url of thing at point or the thing visited in the current buffer."
312330
(interactive)
313331
(if-let ((target (forge--browse-target)))
314332
(let ((url (if (stringp target) target (forge-get-url target))))
@@ -337,12 +355,32 @@ argument also offer closed pull-requests."
337355
(forge-get-url :branch branch))
338356
(and-let* ((remote (magit-remote-at-point)))
339357
(forge-get-url :remote remote))
358+
(and-let* ((file (magit-file-at-point)))
359+
(forge-get-url :blob nil file))
340360
(forge-post-at-point)
341361
(forge-current-topic)
362+
(and (or magit-buffer-file-name buffer-file-name)
363+
(apply #'forge-get-url :blob (forge--browse-blob-args)))
342364
(and magit-buffer-revision
343365
(forge-get-url :commit magit-buffer-revision))
344366
(forge-get-repository :stub?)))
345367

368+
(defun forge--browse-blob-args ()
369+
(cond
370+
(magit-buffer-file-name
371+
`(,(or magit-buffer-refname magit-buffer-revision)
372+
,(magit-file-relative-name magit-buffer-file-name)
373+
,@(magit-file-region-line-numbers)
374+
,current-prefix-arg))
375+
(buffer-file-name
376+
`(nil
377+
,(magit-file-relative-name buffer-file-name)
378+
,@(magit-file-region-line-numbers)
379+
,current-prefix-arg))
380+
((let ((commit (magit-read-local-branch-or-commit
381+
"Browse file from commit")))
382+
(list commit (magit-read-file-from-rev commit "Browse file"))))))
383+
346384
;;;; Urls
347385

348386
(cl-defgeneric forge-get-url (obj)
@@ -369,6 +407,23 @@ argument also offer closed pull-requests."
369407
(forge--format repo 'commit-url-format
370408
`((?r . ,(magit-commit-p commit))))))
371409

410+
(cl-defmethod forge-get-url ((_(eql :blob)) commit file
411+
&optional line end force-hash)
412+
(let* ((commit (or (and (magit-branch-p commit)
413+
(cdr (magit-split-branch-name commit)))
414+
(and commit (magit-commit-p commit))
415+
(and (not (or line force-hash))
416+
(magit-get-current-branch))
417+
(magit-rev-parse "HEAD")))
418+
(repo (forge-get-repository :stub))
419+
(format (oref repo blob-url-format)))
420+
(when (cl-typep repo 'forge-gitweb-repository)
421+
(setq commit (concat (if (magit-branch-p commit) "hb=" "h=") commit)))
422+
(concat
423+
(forge--format repo format `((?r . ,commit) (?f . ,file)))
424+
(and line (forge-format-blob-lines repo line
425+
(and (not (equal line end)) end))))))
426+
372427
(cl-defmethod forge-get-url ((_(eql :branch)) branch)
373428
(let (remote)
374429
(if (magit-remote-branch-p branch)
@@ -393,6 +448,27 @@ argument also offer closed pull-requests."
393448
(cl-defmethod forge-get-url ((notify forge-notification))
394449
(oref notify url))
395450

451+
(cl-defmethod forge-format-blob-lines ((repo forge-repository) line end)
452+
(cl-etypecase repo ;Third-party classes require separate methods.
453+
((or forge-github-repository
454+
forge-gitlab-repository ;Also supports "#L%s-%s".
455+
forge-forgejo-repository
456+
forge-gitea-repository
457+
forge-gogs-repository)
458+
(format (if end "#L%s-L%s" "#L%s") line end))
459+
(forge-bitbucket-repository
460+
(format (if end "#lines-%s:%s" "#lines-%s") line end))
461+
((or forge-cgit-repository
462+
forge-cgit*-repository
463+
forge-cgit**-repository)
464+
(format "#n%s" line))
465+
((or forge-gitweb-repository
466+
forge-repoorcz-repository
467+
forge-stagit-repository)
468+
(format "#l%s" line))
469+
(forge-srht-repository
470+
(format "#L%s" line))))
471+
396472
;;; Visit
397473

398474
;;;###autoload

lisp/forge-forgejo.el

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
(commit-url-format :initform "https://%h/%o/%n/commit/%r")
3838
(branch-url-format :initform "https://%h/%o/%n/commits/branch/%r")
3939
(remote-url-format :initform "https://%h/%o/%n")
40+
(blob-url-format :initform "https://%h/%o/%n/src/%r/%f")
4041
(create-issue-url-format :initform "https://%h/%o/%n/issues/new")
4142
(create-pullreq-url-format :initform "https://%h/%o/%n/pulls") ; sic
4243
(pullreq-refspec :initform "+refs/pull/*/head:refs/pullreqs/*")))

lisp/forge-gitea.el

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
(commit-url-format :initform "https://%h/%o/%n/commit/%r")
3939
(branch-url-format :initform "https://%h/%o/%n/commits/branch/%r")
4040
(remote-url-format :initform "https://%h/%o/%n")
41+
(blob-url-format :initform "https://%h/%o/%n/src/%r/%f")
4142
(create-issue-url-format :initform "https://%h/%o/%n/issues/new")
4243
(create-pullreq-url-format :initform "https://%h/%o/%n/pulls") ; sic
4344
(pullreq-refspec :initform "+refs/pull/*/head:refs/pullreqs/*")))

lisp/forge-github.el

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
(commit-url-format :initform "https://%h/%o/%n/commit/%r")
4141
(branch-url-format :initform "https://%h/%o/%n/commits/%r")
4242
(remote-url-format :initform "https://%h/%o/%n")
43+
(blob-url-format :initform "https://%h/%o/%n/blob/%r/%f")
4344
(create-issue-url-format :initform "https://%h/%o/%n/issues/new")
4445
(create-pullreq-url-format :initform "https://%h/%o/%n/compare")
4546
(pullreq-refspec :initform "+refs/pull/*/head:refs/pullreqs/*")))

lisp/forge-gitlab.el

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
(commit-url-format :initform "https://%h/%o/%n/commit/%r")
4141
(branch-url-format :initform "https://%h/%o/%n/commits/%r")
4242
(remote-url-format :initform "https://%h/%o/%n")
43+
(blob-url-format :initform "https://%h/%o/%n/-/blob/%r/%f")
4344
(create-issue-url-format :initform "https://%h/%o/%n/issues/new")
4445
(create-pullreq-url-format :initform "https://%h/%o/%n/merge_requests/new")
4546
(pullreq-refspec :initform "+refs/merge-requests/*/head:refs/pullreqs/*")))

lisp/forge-gogs.el

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
(commit-url-format :initform "https://%h/%o/%n/commit/%r")
3838
(branch-url-format :initform "https://%h/%o/%n/commits/%r")
3939
(remote-url-format :initform "https://%h/%o/%n")
40+
(blob-url-format :initform "https://%h/%o/%n/src/%r/%f")
4041
(create-issue-url-format :initform "https://%h/%o/%n/issues/new")
4142
(create-pullreq-url-format :initform "https://%h/%o/%n/pulls") ; sic
4243
(pullreq-refspec :initform "+refs/pull/*/head:refs/pullreqs/*")))

lisp/forge-repo.el

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
(commit-url-format :initform nil :allocation :class)
4242
(branch-url-format :initform nil :allocation :class)
4343
(remote-url-format :initform nil :allocation :class)
44+
(blob-url-format :initform nil :allocation :class)
4445
(create-issue-url-format :initform nil :allocation :class)
4546
(create-pullreq-url-format :initform nil :allocation :class)
4647
(pullreq-refspec :initform nil :allocation :class)

0 commit comments

Comments
 (0)