Content AND Presentation

2026-05-09 describe-personal-keybindings

Some time ago one Emacs user made themselves a local web app showing various Emacs keybindings – basically, a web-based Emacs cheatsheet. It’s definitely a nice project even if not for me – if I were to create something like that, it would run in Emacs and not in the browser, it would definitely mention transpose-.* commands, and it would never be dark-mode-only;-). But it’s a really cool and nice project nevertheless!

That’s not the topic of this post, however. In a Reddit discussion about this tool someone mentioned a command that blew me away: describe-personal-keybindings. It is part of the use-package package (which has been part of core Emacs for quite some time now), and it’s purpose is to show, well, all personal bindings of the user.

I ran it in my Emacs (of course), and I was a little disappointed – it only showed less than a dozen keybindings. Surely I have more of them in my init.el! I started to dig a bit and it turned out that in order to see a keybinding in its output, I must use the bind-key macro (only briefly mentioned in the manual). I have to admit that I don’t use use-package much – a good part of my init.el predates its existence, and probably most of my init.el predates its inclusion into Emacs, and frankly I don’t update my init.el whenever Emacs introduces new ways of configuring itself. (For example, some time ago Emacs 29 introduced keymap-set, and I only learned about it recently – thus I have more instances of define-key than of keymap-set in my init.el.) I might convert most of them to bind-key though, since a list of all personal bindings is a very cool thing to have. It’s especially useful because it tells you whether your keybinding overwrote any preexisting one. This means that when one of the keys you have used in your personal bindings, previously unbound, is bound to something in a newer version of Emacs, you can learn about it and decide whether to keep the binding or not.

It’s even better than this, though. The bind-key macro (and its friends) can do more things. See the source to learn more. For example, there is the bind-key* macro, which is “stronger” than bind-key in the sense that it overrides any minor modes which might bind a given key. There is also unbind-key (with obvious semantics) and bind-keys​/​bind-keys* which allow to bind many keys at once.

I have to admit that discovering this package was one of the things that made me decide to refactor my init.el to use use-package and :bind (which uses bind-keys under the hood) more. This change, along with what I wrote a year ago, would be another way of solving the problem of defining some personal settings in my init.el and then forgetting about them. (Although I think that the best way to solve that issue is to add things to init.el very slowly and examining whether they are genuinely useful.)

That’s it for today, until next time!

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

2026-05-02 Node.js reporting

Some time ago I wrote about a new-ish feature of Node where it parses .env files (dotenv-style) itself. Today, I’m going to mention a feature which has been in Node for some quite time, but somehow I’m not sure many people know about it.

We all know and love “printf debugging”, and I have written about its various variants I use quite a few times. However, sometimes just a console.log (or even console.dir) is not nearly enough. For example, you might want to know who called a function you are debugging. Normally, I’d put a console.trace() in such a function, but recently I learned that there is something better – or at least, more comprehensive.

For example, when you run this script with Node.js:

const fn = (arg) => {
        console.log('inside `fn`', arg)
        process.report.writeReport()
}

fn(1)

you get an output looking like this:

$ node report-test.js
inside `fn` 1

Writing Node.js report to file: report.20260330.055029.225164.0.001.json
Node.js report completed

When you look inside the generated json file, you’ll see several hundred lines of debugging goodness. Try it yourself to see what’s in there. Your stack trace can be found under javascriptStack, for example, but there’s a lot more. For example, all your environment variables are listed in the report (which makes it pretty important not to disclose it when they could contain secrets – but you can say process.report.excludeEnv = true to avoid listing them).

Of course, if all you need is a stack trace and you are not really interested in details like memory consumption, CLI arguments, the process id of your Node program or the OS version you ran, you might as well use console.trace. Where this feature really shines is in the ways of triggering the report creation. The writeReport function is just one of them. For example, you can make Node generate a report when an uncaught error is thrown:

const fn = (arg) => {
        console.log('inside `fn`', arg)
        throw new Error("custom exception")
}

process.report.reportOnUncaughtException = true

fn(1)

Other options are fatal error (which may mean a Node.js bug or an OOM error) or – perhaps most interestingly – a signal (SIGUSR2 by default). That means you can set your Node app up to generate a report on demand and request a report with kill -SIGUSR2 <pid>. Head to the docs to learn more about this cool feature!

CategoryEnglish, CategoryBlog, CategoryJavaScript

Comments on this page

2026-04-25 How I use my numeric keypad with Emacs Ledger mode

As the readers of my blog know, I’m a heavy Ledger user. One thing that annoyed me was the fact that I couldn’t use my numeric keypad to enter amounts. The reason was simple – the “comma” key on that keypad inserted a comma in Emacs and not a period. For a long time I suspected that the reason for that was that I had a Polish locale set somewhere in the system (we use a decimal comma in Poland and period is a thousand separator). In fact, I have a mixture of Polish and English locales – I want sorting to work correctly for the Polish alphabet, but I want programs to talk to me in English. One reason is that some programs have very poor translations; a more important one is that searching the Internet for error messages is easier when they are in English.

Anyway, I finally decided to do something about my problem. When I typed C-h c , (pressing the keypad comma), I saw this:

, 'COMMA' (translated from <kp-separator>) runs the command self-insert-command

so I searched Emacs sources for the string kp-separator and found this in simple.el:

;; Make the keypad keys act like ordinary typing keys.  If people add
;; bindings for the function key symbols, then those bindings will
;; override these, so this shouldn't interfere with any existing
;; bindings.

;; Also tell read-char how to handle these keys.
(mapc
 (lambda (keypad-normal)
   (let ((keypad (nth 0 keypad-normal))
         (normal (nth 1 keypad-normal)))
     (put keypad 'ascii-character normal)
     (define-key function-key-map (vector keypad) (vector normal))))
 ;; See also kp-keys bound in bindings.el.
 '((kp-space ?\s)
   (kp-tab ?\t)
   (kp-enter ?\r)
   (kp-separator ?,)
   (kp-equal ?=)
   ;; Do the same for various keys that are represented as symbols under
   ;; GUIs but naturally correspond to characters.
   (backspace 127)
   (delete 127)
   (tab ?\t)
   (linefeed ?\n)
   (clear ?\C-l)
   (return ?\C-m)
   (escape ?\e)
   ))

I’m not sure what (put keypad 'ascii-character normal) does (and searching for ascii-character suggest something connected with the dark arts of terminal emulation, so I decided not to pursue this further to preserve my sanity), but the rest is pretty clear – apparently, the “keypad separator” is hardcoded to enter a comma in Emacs. Well, not that clear – it still touches another murky corner of Emacs, key translations – but at least I knew what to do. I put this in my init.el:

(keymap-set function-key-map "<kp-separator>" ".")

and from now on I can type numbers with decimal part using my numeric keypad.

While at that, I decided to revisit my fast-calc command I wrote about over ten years ago. I figured that since I’m using the numeric keypad, I could make use of the Calc key my laptop has there. I didn’t want to bind it to fast-calc, since pressing C-u Calc to get the value with the currency is not very ergonomic, so I decided to write an auxiliary command which works like fast-calc but with the meaning of the prefix argument reversed. Of course, I also needed to know how to bind the Calc key, but that is easy – when I press C-h c Calc, Emacs tells me what it calls that key. So, here is my fast-calc.el file after the changes.

;; -*- lexical-binding: t; -*-
;; Fast calculation: interactively replace simple arithmetic
;; expressions with their values in arbitrary buffers

(defvar fast-calc-suffix " PLN"
  "The default suffix for C-u M-x fast-calc.  Useful in ledger-mode.")

(defun fast-calc (currency)
  "Replace the arithmetic expression to the left of the point with its
value.  The arithmetic expression is defined as a simple regex match.
With prefix arg, round to two digits after the decimal point and
add the currency suffix"
  (interactive "P")
  (when (looking-back "[-+/*().0-9]\\{2,\\} *"
                      (line-beginning-position)
                      t)
    (replace-match
     (save-match-data
       (calc-eval (if currency
                      (list
                       (concat (match-string-no-properties 0) "+0.0")
                       'calc-float-format
                       '(fix 2))
                    (match-string-no-properties 0))))
     t t)
    (if currency (insert fast-calc-suffix))))

(defun fast-calc-with-prefix-arg-flipped (arg)
  "Call `fast-calc' with the meaning of the prefix arg flipped."
  (interactive "P")
  (fast-calc (not arg)))

(global-set-key (kbd "C-z c") #'fast-calc)
(global-set-key (kbd "<XF86Calculator>")
                #'fast-calc-with-prefix-arg-flipped)

And that’s it. Now using Ledger is even more streamlined for me!

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryLedger

Comments on this page

More...

CategoryBlog