Blog

For the English part of the blog, see Content AND Presentation.

2021-02-27 Visible bell in Emacs

Emacs has this habit of beeping when something goes wrong (or when the user presses C-g). Frankly, this is quite useful, since it is an instant feedback, but there are times when I don’t want that behavior. There are a few solutions then. One of them is just to put your headphones on (and I sometimes do it indeed). But this is Emacs, so there is (as always) a software solution. It turns out that not only can you disable beeping, you can change it into all sorts of things. One of them is to change an audible signal to a visible one. Interestingly, there is no command for this, only a variable. You can say M-x set-variable RET visible-bell RET t RET and now Emacs flashes (parts of) the screen instead of beeping. You can also set the variable ring-bell-function to a function, and then Emacs will call that function instead of beeping – this way you can e.g. lanch a process to play a file with your favorite sound each time you press C-g! Some other possibilities are mentioned in the Emacs wiki page about the bell.

Finally, if you want your Elisp code to beep, the function ding does that. And that’s it for today – happy beeping!

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

2021-02-20 Using keyboard macros to emulate query replace

As you might have noticed, I hardly ever write about TeX anymore. This is because I use it much less these days – apart from my work for Wiadomości Matematyczne (which will end in a few weeks, too) I don’t really need it that much anymore. (Well, I will use it from time to time, of course, for larger writing projects, and there are a few of them on the horizon.)

A few days ago, however, I needed to do something I consider really blogworthy, even though the tip I’m going to share today is (surprise, surprise!) very Emacs-centric.

I was editing a paper which used italics (with the \emph LaTeX macro) really a lot (more than 100 times). Very many (but not all) of its occurrences were to be changed to quotes, so that e.g. \emph{petrichor} should be changed to ,,petrichor’’ etc.

I could do that with query-replace-regexp, of course, assuming that there were no braces within the italic text. As we know, regular expressions are not the right tool if we want to do delimiter pairing. Hence I decided to go another route and use keyboard macros – Emacs has the very useful forward-sexp (and backward-sexp) commands which take nested delimiters into account.

So, I first wanted to have a sequence of keystrokes that would find the next occurrence of \emph and wait for my input. This is easy enough, so I just needed to record the sequence C-s \emph RET C-x q. When playing the macro back, Emacs would stop there and let me press SPC or y to continue or DEL or n to skip the rest of the macro (which is a lot like query-replace). If I want to do the replacing in this particular place, there is one minor gotcha: I can’t replace the opening brace with the opening quote, since then forward-sexp won’t have the correct “starting point”. This means that I want to somehow “store” the position of the opening brace, jump (with forward-sexp) to the closing one, change it into a closing quote, jump back (without backward-sexp, which wouldn’t work now as there is no closing brace anymore) and change the opening brace into an opening quote. Fortunately, Emacs has exactly what I need to store a position in the buffer and jump back to it – the mark. So, here is another sequence of keystrokes to add to my macro:

M-DEL			;; kill the "emph"
DEL			;; delete the backslash
2*C-SPC			;; set mark and deactivate mark (no need for region!)
M-C-f			;; move to the closing brace...
DEL			;; ...and delete it
2*'			;; type the closing quote
C-u C-SPC		;; go back to the opening brace...
C-d			;; ...and delete it
2*,			;; type the closing brace

and that’s it, I finished it with <f4>. Notice that I used double C-SPC so that the region doesn’t get activated – this wasn’t really necessary, single C-SPC would do, too.

And now replacing the italics with quotes is easy: just press <f4> and then y or n, then <f4> again etc.

But wait, that’s not all! I streamlined this process even more. Emacs keyboard macros have this very useful feature where you can tell Emacs to play a macro several times by giving a prefix argument to <f4>. And since recording a macro which finds (e.g. using C-s) a place in the buffer, operates on it somehow and then moves on to the next occurrence is quite a common use-case, you can also give a prefix argument of zero to repeat the macro indefinitely until Emacs beeps (more or less, i.e., until you get an error or press C-g). So, I could now say C-u 0 <f4> and just press y or n repeatedly until I got to the last occurrence when Emacs would beep at me and break out of the macro loop.

Well, of course all this can be done in a different way. One other solution to my problem would be to use multiple cursors – although this one has a drawback in that not all instances of the changed string would be visible at once, and editing things I don’t see is something I really don’t like. I could have used query-replace-regexp anyway, since it just so happened that I didn’t have any braces within my \emph macros. If I knew I wanted to replace all instances, I could use Iedit. Finally, I could define a one-parameter TeX macro \quote putting its parameter in quotes and just query-replace the string \emph with \quote, keeping the parameter (with or eithout braces) intact. But I figured that the trick with keyboard macros, even if not the simplest one, is worth sharing – especially that it can be used with things other than simple replacement, like changing the lettercase etc.

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryTeX, CategoryLaTeX

Comments on this page

2021-02-13 Copying to clipboard with single spaces

I sometimes need to transfer some text from Emacs to another program, like a web browser or terminal. A few weeks ago I thought that it would be nice if I could somehow transform that text – my use-case is changing double spaces (which I habitually put after every sentence, so that I can use Emacs’ sentence-aware commands) to single spaces (which is what most people expect, and some people treat as the only correct option).

Well, it turns out that there is no hook in Emacs to do that – but it’s not really a problem, since there are two ways around it. For starters, I could change the interprogram-cut-function variable (which points to a function doing the actual copying to system clipboard – gui-select-text by default). Or even better, I can advise gui-select-text so that it begins with replacing multiple spaces with single ones. (Note that this means in particular that Emacs’ own kill ring won’t be affected – killing and yanking within the same Emacs session will preserve all the spaces. Going to a separate Emacs process will not, of course, since then the text travels through the system clipboard.)

Now one might think this is going to work:

(defun single-spacify (args)
  "Convert all consecutive spaces to a single one in STRING."
  (list (replace-regexp-in-string " +" " " (car args))))

(advice-add 'gui-select-text :filter-args #'single-spacify)

but it doesn’t. Before I explain why, let me mention two things which were not apparent to me at first. One is that I initially thought that I should use the :before advice combinator – but that was only because I was too lazy too read the manual. That one is only useful when you want to run some code, well, before the function advised, but both the piece of advice you provide and the function being adviced receive exactly the same arguments. In order to modify the arguments the advised function sees, you need to use :filter-args as above (or some more general combinator like :around, of course).

Another gotcha is that the “advisor” (i.e., my single-spacify function) receives a list of all arguments provided to the “advisee” (i.e., gui-select-text in the example above) – hence the car. And the advice mechanism expects it to also return a list of arguments which are then fed into the “advisee” – hence the list. (This is of course documented in the manual, although partially in code and not in prose – but that’s ok.)

Now, unfortunately this is not the best idea. The reason is fairly obvious – if I decide to transfer some code (as opposed to natural-language text) from Emacs to somewhere else via the clipboard, and the code uses spaces and not tabs for indentation, things will break horribly. (Notice that the single-spacify function does not touch tabs.) And before you start to complain that tabs should be used exclusively for indentation, please note that e.g. YAML explicitly disallows tabs for indenting (whether using YAML is a good idea itself is a separate topic).

So, what I think I should do instead is only “compress” multiple spaces to one when they are not at the beginning of a line.

In a typical programming language doing something like this with a (possibly multiline) string would follow a typical pattern: split the string into an array/list of strings on newlines, iterate over all the single lines and then join them back together. I could do this in Elisp, too, using the split-string and mapconcat functions. However, Emacs is a text editor, and much more natural (and idiomatic, I think) solution is to put the string into a temporary buffer, use Emacs’ editing functions to work on it and then convert it back into a string.

So, here is one possible solution.

(defun single-spacify (args)
  "Convert all consecutive spaces not at BOL to a single one in STRING."
  (list (with-temp-buffer
	  (insert (car args))
	  (goto-char 0)
	  (while (not (eobp))
	    (skip-chars-forward " \t")
	    (while (re-search-forward
		    "  +"
		    (save-excursion
		      (end-of-line)
		      (point))
		    t)
	      (replace-match " " t t))
	    (end-of-line)
	    (unless (eobp)
	      (forward-char 1)))
	  (buffer-string))))

Note that I tried to make this function slightly optimized – this might be premature optimization, and since this is going to be used as an advice to an interactive function anyway, these optimization probably don’t matter much, but they don’t really make the code less readable, so why not. For instance, (goto-char 0) is perhaps a tiny bit faster than (goto-char (point-min)), but since we call it right after inserting to a freshly created temporary buffer, (point-min) is going to be 0 anyway. Also, the two t​’s in the replace-match call make it skip two branches in its code – but again, this function is written in C, so most probably nobody would ever notice.

Now what would be interesting is this: how does this compare to a split-string​/​mapconcat solution? I didn’t actually write it (though it would be fairly easy, I guess), but I have a strong suspicion that the more lines we have, and the more actual replacements, the faster the buffer version is going to be. I base this guess on my earlier experiences with strings and buffers in Elisp, one of their differences being that strings are immutable and buffers are not – so if we perform a lot of string operations, the garbage collector will intervene and slow things down considerably.

Anyway, this is it for today. Happy hacking!

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

More...