Showing revision 7

Blog

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

2026-08-01 A fancier splash screen in terminal Emacs

I’ve been using Emacs in a terminal for some time now (an experience worth a blog post another day). One thing that bothered me a little was that the “splash screen” (what Emacs displays at the start) does not show the familiar Emacs logo. I decided to fix this.

The simplest approach I could think of was to generate the logo in ASCII art form and turn some knob to display it in a terminal. It turns out there is no such knob built in – but this is Emacs, so everything can be changed even if the Emacs devs didn’t think of it.

The splash screen is defined in startup.el. A quick scan revealed that on a graphic display, the function fancy-splash-screen is called (which displays the logo), and in a terminal it’s normal-splash-screen (which does not). There aren’t any variables I could find to customize it, but we have advice!

(defun insert-ascii-art-logo-on-splash-screen (&optional startup concise)
  "Insert an ASCII-art Emacs logo on the normal splash screen."
  (unless concise
    (with-current-buffer "*GNU Emacs*"
      (let ((inhibit-read-only t))
        (goto-char (point-min))
        (call-process "jp2a" nil t nil
                      "--invert"
                      (format "--width=%s" (/ (window-width) 2))
                      (expand-file-name "images/splash.png"
                                        data-directory))
        (insert "\n\n")))))

(advice-add 'normal-splash-screen
            :after
            #'insert-ascii-art-logo-on-splash-screen)

ascii-art-emacs-splash-screen.png

As you can see, the code is pretty simple – and the result is actually pretty cool! One thing I’ve learned while writing it was the existence of the jp2a utility; another was the data-directory variable. (If you are bored some day, say M-: (dired data-directory) RET and see what’s there!)

Of course, I could probably make the logo-in-the-terminal look much better with kitty-graphics.el – but where’s the fun in that?

Until next time!

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

2026-07-27 Outlining in programs

One of the Emacs’ “killer apps” is Org mode, and one of the most iconic features of Org mode is visibility cycling. It is no wonder people (including me) want a similar feature in other modes.

Some time ago, I was writing a Node.js script which (as is usual in many programs) could be naturally divided into “sections” which I could then fold. I wrote about Hideshow mode, which provides such a thing for code blocks, but I wanted something operating on a slightly different level, grouping sets of functions to one foldable unit.

My first thought was that it would be great to be able to use pages for that. I imagined creating “headings” like this:

^L// This is a heading

(in case you don’t know, // is JS’ syntax for a line comment), and being able to press TAB on such a line to fold the whole page. I asked the Emacs devs whether it would be possible to extend Hideshow mode to support that (fully aware that it might be much more difficult than it sounds), and to my surprise, I learned that Emacs already has such a feature built in! It is called Outline minor mode, and turning the option outline-minor-mode-cycle on allows to use TAB to cycle (which is a prerequisite for me – I won’t risk breaking my fingers on the default C-c @ C-c and its ilk;-)). It has some more customization options (which see), but it turned out it has another drawback for me: the Eslint configuration used in the project I participate in does not like whitespace before comments. However, adding "ignoreComments": true to that rule fixed the problem.

However, Outline minor mode is neither the only nor the best solution to this issue. Folding in non-Org files is an itch many people have, and there are numerous third-party solutions to it. Evaluating all (or even a few) of them would be tedious and probably counterproductive. I generally tend to stick with built-in solutions for my Emacs needs – third-party packages, while often useful, have some drawbacks. This is definitely the case here – many folding packages are unmaintained, undocumented, bloated, do not support what I’d like, or several of the above;-). After a short research, I found two other solutions which seemed good candidates for my needs.

The first one is called Allout and is built into Emacs, too. It seems fairly feature-rich, but apparently does not support what I’d like the most – visibility cycling on TAB. I don’t care too much about its other features – this is the most basic thing I need, so I decided to look further.

The second one I couldn’t remember, but I do remember that a friend of mine recommended it, and after a short search I found his blog post where he did so. The tool is called outli and after a short experiment I think it’s the solution for me. It doesn’t seem abandoned, has no open issues, it has few but well-thought out features, and it has less than 400 lines of code (compare this to Allout’s 5000+!).

The main advantage of Outli over Outline minor mode is its keybindings. With the point on a headline, tab (un)folds it, p and n move the point to the previous and next headline, and b​/​f move the point to the previous/next headline on the same level. Pressing ? on a headline shows a buffer with a list of these and other keybindings.

The only thing that Outli lacks (in a sense) is an easy way to jump to the previous or next headline when the point is not on one of them. That is not a very big deal, though – Outli uses Outline minor mode under the hood, so you can always press C-c @ C-p or C-c @ C-n to do that. (If you happen to need that often, my advice would be to bind them to C-c C-3 C-p and C-c C-3 C-n instead to avoid the shift/control dance.)

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

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryOrgMode

Comments on this page

2026-07-20 Hideshow mode

Recently I discovered a very cool feature of Emacs. Apparently, it’s been present in Emacs for over 30 years, although the Git log shows that it’s been heavily worked on very recently. Meet Hideshow mode. It’s purpose is simple: it allows to, well, hide or show blocks of code.

There is another feature like this (probably even older), called selective display (in fact, I’ve written about it several years ago). It turns out that Hideshow mode is way better. Its main disadvantage is that its keymap is bound to C-c @, which is probably one of the least ergonomic bindings possible. Apart from that, it’s great. You can press C-c @ C-d and C-c @ C-s to hide and show the current block, or just use C-c @ C-c to toggle the current block’s hide/show status. (You can also click S-mouse-2, that is, shift-click the middle button, if you are a mouse person.) Also, C-c @ C-t hides all top-level blocks in the buffer and C-c @ C-a shows everything. (Go to the manual to see a bit more features.)

But wait, there’s more! If you are brave enough to compile Emacs from the master branch, you’ll get something much better! Very recently, Emacs devs added a few fantastic options to Hideshow mode, and once I saw them, I immediately decided to turn them on.

First of all, you can set hs-display-lines-hidden to t, and then you’ll see the number of hidden lines along with the ellipsis. Then, you can set hs-show-indicators to t to see little chevrons in the fringe whenever there is a block starting in that line that can be shown or hidden. These chevrons can be clicked to toggle the visibility of the block.

One of the coolest features of Hideshow mode is the hs-cycle-filter option. It is nil by default, but you can set it to t so that pressing TAB on a line where a block begins toggles its visibility (via hs-toggle-hiding, that is, like C-c @ C-c). Of course, TAB is usually bound to indent-for-tab-command (at least whenever I edit JavaScript, which is my main use case for Hideshow mode). That’s why I set hs-cycle-filter to #'bolp – this means that the toggling behavior of TAB is only active when the point is at the beginning of line, and I can still use it to fix indentation with point somewhere else.

Now, I’ve saved one thing for the end of this post. There is one more command in Hideshow mode (again, only on the master branch as of writing this): hs-cycle. It works very similar to hs-toggle-hiding, but acts as a three-way toggle between hiding the whole block, showing the block but hiding its nested blocks, and showing everything beneath it. (It also accepts a numerical argument greater than 1 and then hides blocks that many levels underneath.) By default it is bound to C-c @ TAB, but I like it so much that I decided to make it easier to use. Here is what the docstring for the hs-cycle-filter option said pretty recently:
Currently it affects only the command hs-toggle-hiding by default, but it can be easily replaced with the command hs-cycle.
Here, the “easy” part means diving into the source code and changing what needs to be changed:

(keymap-set hs-minor-mode-map
            "TAB"
            `(menu-item
              "" hs-cycle
              :filter
              ,(lambda (cmd)
                 (when (and hs-cycle-filter
                            ;; On the headline with hideable blocks
                            (save-excursion
                              (forward-line 0)
                              (hs-get-first-block-on-line))
                            (or (not (functionp hs-cycle-filter))
                                (funcall hs-cycle-filter)))
                   cmd))))

This is copied almost verbatim from the (defvar-keymap hs-minor-mode-map ...) form in hideshow.el – I just swapped hs-cycle for hs-toggle-hiding. (I have to admit that I don’t fully understand this snippet. I never studied Emacs menus, which are quite a sophisticated feature, and while I obviously have a general idea of how this code most probably works, I’d prefer not to analyze it too deeply – menus in Emacs are something I never use, and that is not something I want to change in the near future.) And now, TAB at the beginning of line when I edit JavaScript works much like in Org mode!

Of course, it would be nicer if Emacs allowed to make this happen without cargo-culting parts of its source code, so I made a feature request to allow to set this up more easily. Lo and behold, Emacs now has it! Elijah Gabe Pérez added a function called hs-add-cycle-binding, which now allows to do this:

(hs-add-cycle-binding nil "TAB" #'hs-cycle)

instead of my (much longer) snippet. Hurray!

The only thing I slightly miss is that Hideshow mode cannot hide pages, which are another feature of Emacs I often use to divide my source files into “sections”. But that is something which can be remedied in another way, and will be a topic of a future post.

Anyway, that’s it for today. I’m definitely going to keep an eye on any further Hideshow mode developments, and I strongly recommend you to check it out – especially when the next Emacs version is released!

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

More...