Strona domowa

Last edit

Summary: English -> English page

Changed:

< //[If this is all Polish to you, click here: [[English]]]//

to

> //[If this is all Polish to you, click here: [[English page|English]]]//


Witam na mojej prywatnej stronie internetowej!

[If this is all Polish to you, click here: English]

Uwaga: z oczywistych powodów nie mogę zagwarantować swojej nieomylności, choć staram się o zgodność tego, co piszę, z Prawdą. Jest również oczywiste, że nie gwarantuję takiej zgodności w przypadku komentarzy. Umieszczenie linku do strony spoza niniejszego serwisu nie musi oznaczać, że podzielam poglądy autora tej strony, a jedynie, że uważam ją za wartościową z takich czy innych powodów.

Marcin ‘mbork’ Borkowski

2026-01-05 Magit and new branch length

Like many Emacsers, I am a heavy Magit user. If you use Magit, I don’t need to tell you how great it is; if you don’t, I suggest you do yourself a favor and try it out.

That doesn’t mean that Magit is ideal, though. It has some issues, though usually very minor ones. Today I’d like to write about something which is definitely not a “Magit issue”, but rather something I personally miss in it.

When I start working on a feature, I create a branch for it. Usually this means pressing b c (magit-branch-and-checkout). Magit then asks me for the branch’s name. I like my branches to have short names (not more than 32 characters). When I see that the name I’ve typed seems long, I can press C-x h M-= (that is, mark-whole-buffer and count-words-region) and see how many characters I’ve typed. I’d prefer, however, to be shown that length while I type.

This turned out to be a bit more complex than I thought it would be. First of all, when you make a mistake while working on functions you have put into post-command-hook, you might make your Emacs unresponsive. (This is exactly what happened to me while working on this very feature. From then on, I experimented with this code in a separate Emacs instance.) Second, it is easy to write a function which shows the length of the minibuffer, suitable to include in post-command-hook, but it’s less obvious how to include it there. My first idea was to add an :around advice to magit-read-string to add that function before calling magit-read-string and remove it afterwards – but this didn’t help when I pressed C-g while typing the new branch name and the code after the invocation of magit-read-string was skipped. After some experiments (and a short chat with an LLM, I have to admit) I think I found a working (though not exactly elegant) solution. Emacs has two hooks which can help with minibuffer shenanigans: minibuffer-setup-hook and minibuffer-exit-hook. They are run when entering and exiting the minibuffer, and the crucial part is that minibuffer-exit-hook is run even when the user exits the minibuffer via C-g.

So, what I decided to do was to set up hooks within hooks. First of all, I defined a simple function which echoes the number of characters in the minibuffer, using the minibuffer-contents function. Then, I created two functions, magit-branch-length--minibuffer-setup-length and magit-branch-length--minibuffer-exit-length, which (respectively) adds and removes the previously defined echoing function from post-command-hook. These functions are supposed to be added to the minibuffer hooks I mentioned above. Then I advised the magit-read-string function so that before it’s run, my hook-adding-hooks are added where they should be. In my previous attempt, I used an :around advice combinator so that these hooks would be removed after exiting magit-read-string, but that didn’t work – the removing code was skipped when I pressed C-g while entering the branch name. So, I defined one more function, whose sole purpose is to remove all minibuffer hooks, and put it in the minibuffer-exit-hook, too. (Of course, it also removes itself from that hooks.) That way, all my code gets properly removed from all hooks when I exit the minibuffer (in any way).

And that was quite a mouthful, right? I suspect there is some easier method to achieve my goal, so if you know one, please do let me know. In the meantime, I’m using this code (and I’m quite happy about having it!), and remembering the hook trickery I devised for this feature in case I need it again some day.

(defun minibuffer-show-length ()
  "Show the length of minibuffer contents using `minibuffer-message'."
  (minibuffer-message "%d characters" (length (minibuffer-contents))))

(defun magit-branch-length--magit-read-string-before (&rest args)
  "Setup the minibuffer so that its length will be shown.
Make it so only the next time the minibuffer is used."
  (add-hook 'minibuffer-setup-hook
            #'magit-branch-length--minibuffer-setup-length)
  (add-hook 'minibuffer-exit-hook
            #'magit-branch-length--minibuffer-exit-length)
  (add-hook 'minibuffer-exit-hook
            #'magit-branch-length--remove-minibuffer-hooks))

(defun magit-branch-length--minibuffer-setup-length ()
  "Add `minibuffer-show-length' to `post-command-hook'."
  (add-hook 'post-command-hook #'minibuffer-show-length nil t))

(defun magit-branch-length--minibuffer-exit-length ()
  "Remove `minibuffer-show-length' from `post-command-hook'."
  (remove-hook 'post-command-hook #'minibuffer-show-length))

(defun magit-branch-length--remove-minibuffer-hooks ()
  "Remove functions added to the minibuffer setup and exit hooks."
  (remove-hook 'minibuffer-setup-hook
               #'magit-branch-length--minibuffer-setup-length)
  (remove-hook 'minibuffer-exit-hook
               #'magit-branch-length--minibuffer-exit-length)
  (remove-hook 'minibuffer-exit-hook
               #'magit-branch-length--remove-minibuffer-hooks))

(advice-add 'magit-read-string
            :before
            #'magit-branch-length--magit-read-string-before)

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

More...