Showing revision 8

Blog

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

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

2026-04-20 How to quickly generate the list of all columns in a PostgreSQL table

It is well-known that select * is an antipattern (except maybe in an SQL REPL). What to do, however, if you have a select * in your codebase and you want to change it to a proper list of column names? Typing them out manually is fine if there are three of them, but what if there are three dozen? Of course, you may ask an LLM for a nice, comma-separated list of all the columns – but I will generate it three times while you are waiting for the LLM’s answer;-)! (Or, your company – or you personally – might have an anti-LLM policy because of privacy concerns.) Here’s how (of course, in psql). First you turn off the “aligned mode” (I assume you have it enabled, which is a sane default) with \a. Then you say \pset fieldsep ',' to use comma instead of the pipe as column separator. And then, just say select * from my_table limit 0 to only show the header. Optionally, say \a again and restore the column separator with \pset fieldsep '|' – but it’s faster to do all this in a separate, temporary psql session and just exit it.

That’s it for today, see you next week!

CategoryEnglish, CategoryBlog, CategoryPostgreSQL

Comments on this page

2026-04-13 Binding TAB in Dired to something useful

I’m old enough to remember Norton Commander for DOS. Despite that, I never used Midnight Commander nor Sunrise CommanderDired is still my go-to file manager these days. In fact, Dired has a feature which seems to be inspired by NC: when there are two Dired windows, the default destination for copying, moving and symlinking is “the other” window.

Surprisingly, another feature which would be natural in an orthodox file manager is absent from Dired: TAB is not bound by its keymap. This means that pressing it results in a “Buffer is read-only” error. I figured that making TAB switch to the other Dired window would be pretty cool – and definitely more useful than just erroring out.

(defun dired-cycle-dired-windows ()
  "Switch to the next Dired window in the selected frame."
  (interactive)
  (select-window
   (cadr (seq-filter
          (lambda (window)
            (eq (buffer-local-value
                 'major-mode (window-buffer window))
                'dired-mode))
          (window-list)))))

(keymap-set dired-mode-map "TAB" #'dired-cycle-dired-windows)

And that’s it! From now on, pressing TAB in a Dired buffer will cycle through all Dired buffer in the currently selected frame.

Now this command could be made more elaborate. For example, it could go in another direction with a prefix argument. (No point for me, though – very rarely do I have more than two Dired windows open at the same time.) It could cycle through all Emacs frames (doable, but much more work for little gain). It could switch to another Dired buffer in the same window if there’s only one (clever, but I’m not sure if useful). That’s not the point – the point I’m making over and over again is that creating little but useful commands like this is a breeze in Emacs. In fact, creating this one took me maybe 10 minutes – and it would be under 5 minutes if not for the fact that I had to look up a few things, like how to get the buffer given the window, how to get major mode given a buffer etc.

As usual, I recommend the late Robert J. Chassell’s Introduction to Programming in Emacs Lisp if you want to learn to write commands like this and mold Emacs to your needs – and my book about Emacs Lisp if you want to see a few more (and more advanced) examples.

That’s it for today, until next time!

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryDired

Comments on this page

More...