Greetings everyone,
After I proposed a new customization interface for Emacs [1], I jumped on the
occasion to rewrite my literate org configuration to replicate this interface
idea there.
I saw many and various configurations files using org, (from where I took some
inspiration when I first started), but I did not came across the approach I am
presenting below. I am sure it will interest many people already using org to
configure emacs (and maybe others to jump into org and try it).
What I had before:
------------------
* package1
#+begin_src emacs-lisp
(use-package package1 ...)
#+end_src
* package2
#+begin_src emacs-lisp
(use-package package2 ...)
#+end_src
What I have after:
------------------
#+TAGS: [ group1 : tag1 tag2 tag3 tag4 tag5 ]
#+TAGS: [ group2 : tag6 tag7 tag8 tag9 ]
filters
---------
group1 : tag1 tag2 tag3 tag4 tag5
group2 : tag6 tag7 tag8 tag9
* package1 :tag1:tag2:
** option1 :tag3:tag4:tag5:
- [ ] choice1
- [X] choice2
- [ ] choice3
** option2 :tag4:tag5:tag6:
** option3 :tag5:tag6:tag7:
** install
** load/enable feature
** keymap/keybinding
* package2
same here.
So what I did, is that, I removed almost all (use-package) declarations. Some
of the main advantages are :
- allow tagging options individually, and easily find them later.
- allow adding org comments for each option separatly, (and even sometimes for
a given choice).
- easily reference (via org links) other options individually, from within org
comments.
- Also IMO, for new users for example, it is easier to read and understand this
org configuration, than to see a (use-package) declaration. It is true that
org comments will help, but also new users won’t have an additional step to
learn use-package.
- it introduces new users directly to Emacs Lisp functions, like hook
functions, etc, which make it easier for them to learn Emacs Lisp, and also to
easily hack things to their preferences.
- this also allows sharing more granular code snippets (as needed), instead of
having to copy a whole (use-package) declaration, and sometimes without really
understanding what the declaration (or a part of it) is supposed to do, and how
someone is supposed to tweak it, without breaking anything (and without having
to learn use-package, as a prerequisite).
This is not a with/against use-package discussion at all (please don’t divert
from the main idea). The main reason I removed use-package is to be able to
_tag options individually, to easily find them later_ , (for this, I wanted
each org code-block to be totally independent from all others code-blocks).
This is the fundamental idea behind this new literate config approach (besides
the other advantages it provides, which are numerous)
I will explain briefly each part :
Filters:
--------
These are org links (ex. [[mytagfilter:tag1][tag1]]). Clicking on tag1 for
example, will show only options tagged as “tag1” (and at the same time, will
hide other irrelevant tags that makes no sense to select anymore). It is a
known filter mechanism, and is not specific to this approach. (I hope if org
maintainers and/or contributors can implement this in org, because I find it
useful in all my org files. I think many would find it useful too.)
Install:
--------
Is how to install the package. This is still work in progress, but this is how
I imagine it :
** install
- [ ] immediately
call package functions directly.
- [ ] at the end of the init
append the package name in a variable and install the packages at the end.
- [ ] etc
other installation methods.
Maybe use-package or others can be (temporary) used here, if someone wants to
(for its installation part). Use-package can still be used, anywhere someone
find it useful, it is not mandatory to completely remove use-package (but only
for a single purpose). Emacs is hackable after all, and everyone can use
whatever they want.
Options:
--------
** option
- [ ] choice1 (default)
The default value should not be tangled into the init file.
#+begin_src emacs-lisp
(setopt option defaultvalue)
#+end_src
- [ ] choice2
#+begin_src emacs-lisp
(setopt option value2)
#+end_src
- [ ] choice3
#+begin_src emacs-lisp
Sometimes user needs to write complex regex.
#+end_src
- [X] choice4
#+begin_src emacs-lisp
Sometimes user needs to add/remove hooks.
Sometimes user needs to do that for specific mode(s).
#+end_src
- [ ] choice5
#+begin_src emacs-lisp
Sometimes user needs to write a complex functions.
#+end_src
- [ ] etc
Some may say it is sometimes difficult to divide some options into more
granular choices that can be checked/selected individually, (ex. when the
option is a hook, list, etc.), but I managed to do so successfully for the
moment. (Maybe because my setup is not too complicated ?). If someone can
think of, or find in their config, an option that cannot be divided into
comprehensive choices like above, we can maybe discuss it, but I think there
should be a way to do that, even if sometimes there is little bit of
overlapping (not mutually exclusive choices).
load/enable feature:
--------------------
This is to load/enable a package/feature. Example :
* which-key
** load/enable feature
- [ ] disable (default)
[ ] enable immediately
#+begin_src emacs-lisp
(which-key-mode)
#+end_src
- [X] enabled after emacs idle delay
#+begin_src emacs-lisp
(run-with-idle-timer 2 nil #'which-key-mode t)
#+end_src
- [ ] enabled immediately after feature1 is loaded
#+begin_src emacs-lisp
(eval-after-load 'feature1
'(which-key-mode))
#+end_src
- [ ] enable manually (autoload when which-key-mode is called)
[ This is just an example. which-key-mode is already autoloaded ]
#+begin_src emacs-lisp
(unless
(fboundp 'which-key-mode)
(autoload #'which-key-mode "which-key" nil t))
#+end_src
- [ ] etc
These are also general choices examples, no need to add them all for every
package, only when it make sense. (I usually tend to defer loading features,
in a way or other, so emacs starts faster).
I wish I could share my org config file, but it is still work in progress, and
I also need to do a lot of cleanups before having something shareable, and I
don’t really have time to do so.
So I preferred at least, to share the idea with you all, so you can explore it
from now, and convert your config, if you find it useful. Also for people who
wants to jump into org literate config and haven’t done so yet, maybe they can
consider this approach from the very start.
Also, if someone have time, and can start a project including an org file, and
begin with few packages, then we can start sharing our code snippets (specially
for complex configurations), so we can have a central configuration for
everyone to use (new/non-new users), while being able to pick and choose the
needed package(s), and how to install them, and also to easily tweak
everything, with many choices to select from.
We can also add buttons/links (for new users) to select a given choice, and to
save/tangle the modifications into the init file. (I am adding/removing
“tangle” header arguments, and calling ‘org-babel-tangle’ manually for the
moment. Not complicated after all). The org file can also be enhanced in many
other ways.
If we want to also tag and/or reference individual option’s choices, (which I
find very useful in many cases), we should use org headings instead of org
lists.
There is not need to argue which archive, package or option to include/exclude,
etc. We can include literally everything. Anyone can send his favorite
package(s), option(s), and even individual choice(s), and also the favorite
method to install a package, etc.
A problem I can see, is when we will have a lot of packages. So maybe then we
can separate each package into his own org file, while having a single main org
file containing the tags/filters. The tag filtering should be made to work
just like it works today for org agenda files. If org experts can give us some
advice on if it is something reasonable to do, and what is the best approach.
Another thing, is how we can implement a way to keep someone’s local config org
file(s) synced with the central config org file(s)’s modifications, without
loosing local customizations. (Maybe we can assign an org id to each choice).
There may be other things to take into account too. But we should not consider
anything as blocking. Because having a central place where we can share all
our config efficiently, is already a good thing in itself, and outweigh any
other secondary inconvenience.
So if someone has time to do so, I think it is a very good idea, instead of
every person struggling on his own through the exact same difficulties, and
spending the same amount of time and energy in building their individual
configuration file over the years, and without having a way to share them
efficiently, so everyone can benefits from each other valuable work.
If an org file like this can exist, I think the “emacs is difficult to start
with” will be from the past, and the same can be said for “maintaining one’s
init file over time”. If I could find an org file like this when I first
started, it would have spared me an enormous amount of work and research, and I
think this would be the same for others.
Although there are a lot of org literate config everywhere, (and non-literate
too), they almost all use use-package declarations, which _as a new user_ , I
found difficult to understand and tweak, unless I learn use-package and some
Emacs Lisp before-hand.
With this approach, all you have to learn is org markup (not really after all,
it is just a normal text file). You open emacs, then you open this org file,
then you read a 2min quick intro about how to use it, and you are ready to go :
- you can directly customize emacs (even with very advanced customizations)
- you gradually learn Emacs Lisp, by looking at the code-blocks from time to
time.
- you can even change some customizations, by copying code-blocks and modifying
them as needed, when you have enough Emacs Lisp knowledge.
I tried to keep the presentation as short as possible, while still being clear
enough. If there is something unclear or important but missing, let me know.
Thanks in advance,
[1] https://lists.gnu.org/archive/html/emacs-devel/2024-12/msg00344.html
[ I am not sure which mailing list is the appropriate one. ]
[ Maybe this can be a step before implementing option’s tagging and filtering
natively into Emacs. ]