Some time ago I wrote about a snippet of Elisp for copying my current location. I’ve been using that snippet all the time, and soon I discovered two of its limitations.
First of all, the idea to show the path relative to the .git
file (i.e., the root directory of a project) was not optimal. It turns out that it’s even more useful to have the very root directory attached, too, basically showing the path from one directory above (or is it below?) the project root. Otherwise it may not be entirely clear which project the file belongs to.
Then, the line number is not always needed; sometimes I need just the filename. Seems like a perfect job for a prefix argument! Note that even if the argument is non-nil, the command still obtains the line number and promptly throws it away. I could save a few cycles by not doing that, at the cost of making the code a bit more complicated and possibly less DRY, but I decided not to.
So, here is the updated code. (Note how I use the \\[...]
construct to display what by default is C-u
in the docstring. In recent Emacsen, it even makes the keybinding active, enabling you to see the docstring of universal-argument
after pressing RET
or clicking on it.)
(defun copy-current-location (no-line-number) "Show the current location and put it into the kill ring. \"Location\" means the filename and line number (after a colon). Use the filename relative to the parent of the current VC root directory, so it starts with the main project dir. With \\[universal-argument], the line number is omitted." (interactive "P") (let* ((file-name (file-relative-name buffer-file-name (file-name-concat (vc-root-dir) ".."))) (line-number (line-number-at-pos nil t)) (location (format (if no-line-number "%s" "%s:%s") file-name line-number))) (kill-new location) (message location)))