Ini-style Emacs Configuration Files?

Sunday, 26 October 2025

I while back I wrote up a sketch to interpret Ini-style configuration files for Emacs. Here I want to present and discuss the idea briefly.

Syntax

For those wondering how a “ini-style init file” looks like (I certainly would), I translated parts of my init.el into a syntax that ini.el can handle, to give an idea of how these files look like:

enable inhibit-startup-screen
set mode-line-compact long
set font-use-system-font t
disable menu-bar-mode

bind C-c k compile
eval set compile-command (format "make -k -j%d " (num-processors))

[package avy]
unset avy-single-candidate-jump 
global bind C-z avy-goto-word-or-subword-1
[/package]

add-hook text-mode-hook flyspell-mode
add-hook prog-mode-hook flyspell-prog-mode

[feature flymake]
bind M-n flymake-goto-next-error
bind M-p flymake-goto-prev-error
(defalias 'list-issues #'flymake-show-buffer-diagnostics)
[/feature]

[package bash-completion]
(bash-completion-setup)
[/package]

[package proof-general]
[package focus]
[package markdown-mode]

add-hook before-save-hook time-stamp

The idea here is to do the right thing most of the time, while still allowing for arbitrary complicated configurations using Eli’s, as lines that start with an opening parenthesis are just regular Lisp expressions that treated just like they would be in an init.el.

More details on the syntax can be found in the ini.el file under the “Syntax” section.

Comparison and potential advantages

There are three main approaches to configuring Emacs that one can compare this idea to:

  1. A plain and simple init.el,
  2. The usage of configuration macros like the well known use-package or my not well known setup.el,
  3. A customize-centric approach, which usually means not writing Elisp on your own.

I consider my approach to be a merge of the first two. Settings like bind and set are mapped directly to their obvious corresponding S-expressions. Depending on the exact command and modifiers the concrete replacement might differ, but the point is that it does what you want it to do. You cannot bind keys in a map before the map has been loaded, so the bind M-n flymake-goto-next-error above will expand to

(with-eval-after-load 'flymake
  (keymap-set flymake-mode-map "M-n" #'flymake-goto-next-error))

You can of course just write this out directly, as any line beginning with an opening parenthesis is read directly and interpreted directly. The connection to configuration macros is that this allows us to just express what we want to (“bind this command”), without having to write what we have to (“… after loading this feature”).

The main advantage of my advantage I see is that the syntax is more conventional and thus easier to adopt for some people who are not yet familiar with Lisp, and haven’t internalised what to quote and when. I would claim that for most packages, the keywords I have defined up until now will cover well over 90% of the use-cases. The fact that set expands to setopt also means that it is easy to respect user options as user options and not mistreat them as symbols. Prior to the addition of setopt in Emacs 28, it was necessary to use customize-set-variable, which much like set required user option names to be quoted and would only set a single user option per expression. I think a good maxim of design is to make it easy to do the right thing, where “easy” and “right” are intentionally kept vague. Looking through my init.el, I notice patterns such as the fact that most user options I set are either self-evaluating forms or quoted, so it made sense for me that set would be non-evaluating by default as well.

Another advantage of the simpler but rigid syntax is that I can imagine an extension to customize that can reasonably figure out what to change in a init.ini file, which is much more difficult in a general elisp file, as we have no notion of structure such as the feature or package blocks I have proposed above. This would serve to bridge the gulf between generated custom-set-variables blocks that many users sadly discard by setting custom-file to "/dev/null" and the manually written configuration file. I have heard many people dismissing the customize interface just due to the reason that it generates code that they do not want in their init.el, which I think is a shame.

So now what?

The initial sketch appears to work, though I have to admit that I am not using it personally yet, as I don’t have a need to switch myself and seldom adjust anything anymore in my init.el (remember, compulsive and constant tweaking of configuration files is a sign that you are doing something wrong!). So I would be interested in the opinions of new and intermediate users as to the potential advantages and pitfalls of this idea. Feel free to send me a message with your unfiltered opinions or to share this page with someone who might be interested.

If this idea seems interesting, it would be worth developing into a proper package, with good error messages and syntax highlighting. If it is well received and reliable, it would be interesting to consider merging it into Emacs itself one day.