Alex Carney

Mastodon
  • Blog
  • Code
  • Dotfiles
  • Notes
Metadata
Apr 30, 2025
  • #emacs
  • #git
  • Getting the permalink URL to a line of code
    • Owner and Repo
    • Commit
    • Filepath
    • Start and End
Related
My Emacs Configuration
  • TIL: Local LLMs with Ollama and gptel
  • Using git from Emacs
    • TIL: Additional magit keybindings
    • TIL: Navigating History with Magit
    • Getting the permalink URL to a line of code
  • Cusomising the Emacs Modeline
  • Python in Emacs
  • Language Servers in Emacs
  • Building Emacs from Source
    • Intstalling Emacs with systemd-sysext

Getting the permalink URL to a line of code¶

When writing responses to issues on GitHub, I often find myself wanting to grab the permalink to a specific piece of code. Up until now I’ve always just clicked around the UI until I’ve found the piece of code I’m looking for.

However, surely I can convince Emacs to generate the correct URL for me?

Permalinks on GitHub have the following structure:

https://github.com/<owner>/<repo>/blob/<commit>/<filepath>#L<start>(-L<end>)

So building the URL should be “just” a case of looking up the relevant info and joining it all together!

emacs/lisp/alc-git.el
(defun alc-git-permalink-to-kill-ring ()
  "Construct a permalink URL for the current line or region and place it on
the kill-ring"
  (interactive)
  (if-let* ((repo (alc-git-get-remote-url))
            (commit (alc-git-get-commit))
            (filepath (alc-git-get-filepath))
            (pos (alc-git-get-position))
            (path-start (format "%s#L%s" filepath (nth 0 pos)))
            (url (s-join "/" `(,repo "blob" ,commit ,path-start))))
      (kill-new
       (if (nth 1 pos)
           (format "%s-L%s" url (nth 1 pos))
         url))
    (message "No permalink found")))

Owner and Repo¶

It’s easy enough to get this information from the configured remotes of the git repository. I was a bit surprised not to find a function that already did this in either vc or magit, though it did finally give me an excuse to learn about condition-case

emacs/lisp/alc-git.el
(defun alc-git-get-remote-url ()
  "Return the url of the remote associated with the current buffer.

Prioritizes 'upstream' but will fall back to 'origin' if it is unavailable."
  (condition-case err
      (vc-git-repository-url buffer-file-name "upstream")
    (error err
           (condition-case err
               (vc-git-repository-url buffer-file-name "origin")
             (error err nil)))))

Commit¶

Getting the commit of the current file is easy enough with vc-working-revision however, it would be nice to figure out how

  • to adapt this to also work when viewing an older version of a file with magit

  • to check if the current commit exists on the remote

emacs/lisp/alc-git.el
(defun alc-git-get-commit ()
  "Return the commit hash for the current file"
  (vc-working-revision buffer-file-truename))

Filepath¶

The filepath of course needs to be relative to the root of the repository

emacs/lisp/alc-git.el
(defun alc-git-get-filepath ()
  "Return the filepath of the current buffer relative to the root of the
repository"
  (string-remove-prefix (vc-git-root buffer-file-truename)
                        buffer-file-truename))

Start and End¶

emacs/lisp/alc-git.el
(defun alc-git-get-position ()
  "Return the start and end line number"
  (if (region-active-p)
      `(,(line-number-at-pos (region-beginning))
        ,(line-number-at-pos (region-end)))
    `(,(line-number-at-pos) nil)))
emacs/lisp/alc-git.el
(provide 'alc-git)
Links
  • Page Source
  • Source Code
Built with
  • Sphinx v8.2.3
  • Feather Icons