Content AND Presentation

2022-06-20 Copying the current location

Continuing the trend of playing around with copying stuff from Emacs to the system clipboard, today I’d like to talk about a command I wrote a few days ago. When I chat with a team member about some piece of code we are working on, I often need to tell them where I’m looking. This means the file name and usually also the current line number. While it is very easy to get the current line number (although be careful with narrowing – the number displayed in the modeline only counts the lines in the visible portion of the buffer! Give line-number-at-pos a non-nil second argument to get the “real” line number), the filename is slightly tricky. On the one hand, just the filename (without the path) is sometimes not enough – it sometimes happens that a project contains two distinct files with the same name, just in different directories. (This is probably a bad practice and we usually avoid it, but it happens sometimes.) On the other hand, I don’t want to copy the full path (even if it is easy to get in Dired with dired-copy-filename-as-kill, bound to w by default, with a zero prefix argument) – no need to tell people the directory structure of my drive, down to /home/mbork/. What I need is the filename relative to the directory containing the .git subdirectory (which means the root directory of the current project).

Emacs Lisp to the rescue – it turns out that it took me less than 15 minutes to come up with this.

(defun current-location ()
  "Show the current location and put it into the kill ring.
Use the filename relative to the current VC root directory."
  (let* ((file-name (file-relative-name buffer-file-name (vc-root-dir)))
	 (line-number (line-number-at-pos nil t))
	 (location (format "%s:%s" file-name line-number)))
    (kill-new location)
    (message location)))

It should be pretty self-explanatory, and if you do not know any of the functions involved, go check its docstring. Yet another testimony to Emacs’ flexibility – and easiness of extending it according to your needs.

(Just to remind you: if you want to learn Emacs Lisp and be able to write such little functions for yourself, best start with the late Robert J. Chassell’s excellent – and free! – An introduction to programming in Emacs Lisp. And if you want to learn more, either dive straight into GNU Emacs Lisp Reference Manual, or cough up a few bucks for my book, Hacking your way around in Emacs. As a teaser, let me just briefly mention that I will upload a small update of that book pretty soon, i.e., within the next few weeks!)

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

2022-06-13 Highlighting and de-highlighting things

From time to time I want to perform a kind-of “human search” on a file. For example, there is some keyword – or maybe something describable by a regex – and I want to be able to easily spot all of its occurrences in some file. For some reason, isearch or Swiper won’t work for me. (This may happen if, for instance, I don’t exactly know what I’m looking for. Imagine going through some file and deciding to search for some keywords only when I actually see them for the first time. So, I’m skimming a buffer and once I see the word “banana”, I go “hey, bananas are good, let’s find more of them” and then I want to easily see every line containing the word “banana”. Skimming further, I can see the word “apple” and I suddenly have a craving for apples, so I want to add apples to things that should be easily seen. And so on.)

It turns out that Emacs has a few commands which can help with that. One is highlight-regexp (it should be fairly obvious what it does; by the way, I mentioned it a few years ago); another one is highlight-lines-matching-regexp (also pretty self-explanatory). A slightly less obvious one is highlight-phrase (it is similar to highlight-regexp, but it interprets a space as “match any number of spaces or tabs”). Yet another one is highlight-symbol-at-point. You can also use unhighlight-regexp to cancel the highlighting. (A nice touch is that if you use the highlighting commands more than once, unhighlight-regexp allows you to choose which one to cancel. Also, you can see them all – and a few others – if you press M-s h C-h, since they are bound to a keymap bound to M-s h.)

One thing that occurred to me a few days ago is that these commands can be used to achieve the opposite effect, too – in essence, you can “unhighlight” (is “lowlight” a word?) a regex, a line containing one etc. The trick is that most of the highlighting commands (for some reason, highlight-symbol-at-point is an exception – you have to use a prefix argument to change that) allow you to choose the color used for the highlighting (in Emacs parlance, the face). You see, one of the faces defined by default in Emacs is called shadow, and it means just gray foreground and unchanged background. This means that “highlighting” stuff with that particular face makes it “dimmed”; also, since the highlighting commands employ the font-lock mechanism in a way that any highlighting overrides the standard font-lock, any syntax-related fontification is gone once you use the shadow face with the highlighting commands. (I wish I knew how it is done. I thought it uses font-lock-keywords, but apparently it does not.)

Anyway, the highlighting commands are a great way to temporarily make some text stand out – or fade out, so to speak. Definitely not something you would use every day, but can be very handy once in a while.

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page


CategoryEnglish, CategoryBlog