Blog

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

2020-11-30 Repeating complex commands

Today I learned about a fantastic Emacs feature I had no idea about.

I knew that the key C-x z is bound to the repeat command, which, well, repeats the last (simple) command – I even use it from time to time.

I had no idea, however, that there is another command which can repeat “complex” commands – i.e., ones that use the minibuffer to accept some input. It turns out that if you press C-x ESC ESC (repeat-complex-command), Emacs will convert the last command that used the minibuffer to an Elisp function call and put it into the minibuffer for you to possibly edit and confirm by pressing RET.

I am not sure if – or how often – I might need it to actually repeat commands, but it might actually be useful to budding Elisp programmers to quickly and easily convert human actions into Elisp code. Also, it is insanely cool;-).

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

2020-11-23 Emacs and the X selection

One thing I have been reading about lately is the interaction between Emacs and the outside world via the clipboard. Of course, Emacs predates the clipboard by a lot, but it interacts with it pretty nicely. I have a blog post about that in the works, but it’ll need a bit more work, and I’m really busy now (again…), so for today I only have a short tip.

Instead of using the clipboard – at least on GNU/Linux and X Window – you can use the “primary X selection”, which works by first dragging a portion of text (which sets and activates the region in Emacs) and then clicking the middle mouse button where you want to paste it (in Emacs or somewhere else). This is very useful (and can be made even more useful with mouse-yank-at-point set to t, which see), but the “selection” (“active region” in Emacs lingo) is rather volatile (even if less so than in other software), as the manual asserts.

Enter the secondary X selection. It works basically like the primary one, with the following two differences.

  1. It seems to be more “stable” - apparently, it survives quite a lot of editing commands, to the point some people don’t know how to turn it off.
  2. It is created with the Meta key and usual mouse actions (more or less – again, see the manual for details).

This makes it potentially useful to e.g. repeatedly paste some text even if the clipboard or the primary selection is changed. The drawback is that it is mouse-based, but if you use the mouse, this can sometimes be a nice alternative to using e.g. text registers (which are my go-to feature if I need to paste more than one text repeatedly).

Interestingly, there is a way to create a secondary selection without using the mouse. The function secondary-selection-from-region sets it to the active region. For some reason it is not interactive – I have no idea why. I might be tempted to write some functions to be able to use the secondary selection with only keyboard… (There is the second-sel.el package which might also be helpful, though it might also be overkill, depending on your taste and needs.)

OK, so that’s it for today – expect more about copying/pasting in the future!

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

2020-11-16 Putting punctuation after closing parens automatically

I (obviously) use Emacs a lot for programming. While I would be quite happy to code in Lisp all the time, the reality is the reality, and I do mostly JavaScript.

(Warning: rant time. You might want to skip the next paragraph.)

And you know what? I don’t really get all the hate about JS. After all, it pays my bills. ;-) But seriously, yes, its syntax is broken here and there, its standard library sucks, and the comunity’s NIH attitude (it’s a day off today, what do I do? I know, I do a new JS framework!) is perhaps a bit childish. But every language has its share of issues, and while JS is far from perfect – maybe even in the lower part of the spectrum, though I doubt it – it has reasonable semantics (after all, it’s a Scheme at heart, only with bad syntax), it has a clever object system, it improves every day, and it has pretty good tooling. And – last but not least – I’d choose a good team using a bad language over a bad team using a good language every single day, and happily, I don’t have to, ‘cause that’s what I have already.

OK, enough ranting. Here’s the thing: there are some things that annoy me in my daily work. One of them is this. Assume that I define a function called main, and I want to, well, call it. I type the letters m, a, i and n, followed by an opening paren, and Emacs with its Smartparens mode inserts the closing paren for me (but leaves the point between the parens, so that I can type in the arguments).

So far, so good. But I also happen to use Flycheck, and it uses Eslint under the hood, and Eslint now complains that this line does not end with a semicolon. (And yes, I know about ASI, which is one of the more stupid parts of JS, and OTOH the whole semicolon stuff which percolated from C to JS, Java etc. is absurd, especially compared to the elegant beauty of Lisp’s parens – but we do end lines with semicolons in our team, that’s just what we do, shut up.)

So, to satisfy my OCD (and I’m not mocking people with actual OCD here, mind you – I am fairly confident that I’m a relatively mild case myself, which is annoying sometimes), I need to go to the EOL, put the fu…nny semicolon there and back up to between the parens, and only then can I think about the actual argument list or whatever.

Except that I don’t really have to. This. Is. Emacs!

Look, I don’t want Emacs to put those semicolons for me automatically every time I press the opening paren, or curly brace, or a bracket. That would be way too aggressive – after all, sometimes I might want a comma after the closing delimiter, sometimes I might not need anything. But what if pressing that semicolon when the point is to the left of a closing delimiter would put that semicolon after the delimiter? The key observation here is that in JS, you never want a semicolon right before a closing delimiter. (Well, hardly ever – it is possible to think of a situation when you do. But in these exceptional cases, you can always say C-q ; and you’re good.)

It turns out that there is a very easy way I can make my life easier in this case. Here’s the idea. Let us make the semicolon key move first past any number of closing delimiters to the right of the point, insert a semicolon there, and get back to where we were.

(defun self-insert-after-closing ()
  "Move past any closing delimiters and call `self-insert-command' there."
  (interactive)
  (save-excursion
    (skip-syntax-forward ")")
    (self-insert-command 1)))

That’s how simple it is! I can now just bind the semicolon to this newly defined command and I’m good to go! The skip-syntax-forward function is quite useful, since I don’t need any regex magic here, just an Elisp primitive.

Except this is not the whole story. Now that I have this, I may also want to do the same thing to the comma (that way, you can put a function call as one of the things in an array, for instance, using my nice trick). That, however, is not as simple as it sounds. You have legitimate reasons to put a comma to the left of a closing paren in JS – and that happens when you are typing the argument list. If you have main(arg1*), where the point is where I put the asterisk, pressing the comma key should really put it there. So, I figured that I should modify my function to only perform its magic when the point is between delimiters – being to the left of a closing delimiter but to the right of something else than an opening one is not enough. Happily, the skip-syntax-... functions return the number of characters they skip (negative in the case of the backward variant), so here it is.

(defun self-insert-after-closing ()
  "Insert the character typed, after closing delimiters if necessary."
  (interactive)
  (if (zerop (save-excursion (skip-syntax-backward "(")))
      (self-insert-command 1)
    (save-excursion
      (skip-syntax-forward ")")
      (self-insert-command 1))))

This is substantially more complex (though still took me less than 5 minutes coding), but works much better. Still, it breaks in legitimate cases like a(b(*)), where the comma should be put after the first closing paren but before the second one. (Also, in such a case my function is not very useful anyway, but let’s disregard that for now.)

So, finally, here is the best version I came up with. It is still not ideal (it doesn’t care if the delimiters match, so in cases like [(*}) it will just happily put a comma/semicolon after the closing ) – but then, it is not at all obvious what it should do then), but it should cover 99% of use cases, which is certainly good enough for me.

(defun self-insert-after-closing ()
  "Move past any closing delimiters and call `self-insert-command' there."
  (interactive)
  (let ((opening-before-point-count (save-excursion (- (skip-syntax-backward "("))))
	(closing-after-point-count (save-excursion (skip-syntax-forward ")"))))
    (if (and (> opening-before-point-count 0)
	     (> closing-after-point-count 0))
	(save-excursion
	  (forward-char (min opening-before-point-count closing-after-point-count))
	  (self-insert-command 1))
      (self-insert-command 1))))

And this is pretty much it for today. (Of course, it’s not the end of the story – for instance, it should really be turned into a minor mode etc. But these are just technicalities I’ll save for another time.)

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

More...