Emacs literate config with Guix

Hi! May I ask if someone here can enlight me on what’s the right way to setup literate config with Emacs and Guix?

Here’s my situation:

I am not ready yet to use Guix as a system distro and I am using it as package manager.
I use guix home to setup all my user configs and packages and suprisingly, Emacs is the one is giving me more headaches.

To configure Emacs, I have a small init.el file that loads several org-mode files separated by topics:

   1 (require 'package)
   2 (require 'warnings)
   3 (require 'mu4e)
   7 (org-babel-load-file "~/.config/emacs/general.org" t)
   8 (org-babel-load-file "~/.config/emacs/org-mode.org" t)
   9 (org-babel-load-file "~/.config/emacs/email.org" t)
  10 (org-babel-load-file "~/.config/emacs/rss.org" t)
  11 (org-babel-load-file "~/.config/emacs/music.org" t)
  12 (org-babel-load-file "~/.config/emacs/dev.org" t)
  13 (org-babel-load-file "~/.config/emacs/misc.org" t)
  15 (setq custom-file (locate-user-emacs-file "custom-set-variables.el"))
  16 (load custom-file 'noerror 'nomessage)

All these files need to be tangled when Emacs starts, so I’ve had to add them one by one on the home-xdg-configuration-files-service-type. Adding the emacs directory recursively turns the whole $HOME/.config/emacs directory read-only and emacs fails to start when tangling them:

 136     ;; xdg-files
 137     (simple-service 'xdg-config-files home-xdg-configuration-files-service-type
 138               `(("emacs/init.el" ,(local-file "/home/jaume/src/me/dotfiles/emacs/init.el"))
 139                ("emacs/general.org" ,(local-file "/home/jaume/src/me/dotfiles/emacs/general.org"))
 140                ("emacs/org-mode.org" ,(local-file "/home/jaume/src/me/dotfiles/emacs/org-mode.org"))
 141                ("emacs/email.org" ,(local-file "/home/jaume/src/me/dotfiles/emacs/email.org"))
 142                ("emacs/rss.org" ,(local-file "/home/jaume/src/me/dotfiles/emacs/rss.org"))
 143                ("emacs/music.org" ,(local-file "/home/jaume/src/me/dotfiles/emacs/music.org"))
 144                ("emacs/dev.org" ,(local-file "/home/jaume/src/me/dotfiles/emacs/dev.org"))
 145                ("emacs/misc.org" ,(local-file "/home/jaume/src/me/dotfiles/emacs/misc.org"))
 146                ("emacs/authinfo.gpg" ,(local-file "/home/jaume/src/me/dotfiles/emacs/authinfo.gpg"))

(I know I have to find a better way to refer source files rather than use the whole path…)

The problem I have now is that the files get tangled and emacs starts correctly… the first time. Everytime I change my Emacs config and run guix home reconfigure I need to delete all the tangled el files previously for the changes to take effect. Otherwise emacs seems happy with the previous ones and doesn’t ‘retangle’ them. Maybe because org-files are actually links and doesn’t detect the change? IDK.

How do you people do it? What I am doing wrong on my setup?

Thanks in advance!

Not sure exactly why the structure is this way, but you probably could use something like this to clean it up:

(let ((org-files (directory-files "~/dotfiles/emacs" t "\\.org\\'")))
  (cl-loop for file in org-files
           do (org-babel-load-file file)))

I don’t think there is a reason to symlink your org-files as you do now with guix home, but one option would be something like this:

(service home-dotfiles-service-type
		  (directories '("/home/jaume/src/me/dotfiles"))
		  (excluded '(".*~" ".*\\.swp" "\\.git" "\\.gitignore"))
		  (layout 'plain)))

to symlink all files in your dotfiles directory. At least if I understood your issue correctly.

Hope this helps!


Thanks a lot for the tips @thanosapollo ! Now my guix and emacs config files look much cleaner! I never dared to try the home-dotfiles-service-type but definitely it is worth the change.

However. I still have the same problem: org files don’t get tangled into el files when emacs starts and even if I change my org files, I still start emacs with old configs. For instance, note the el file is one hour older than the org file:

-rw-r--r--  1 jaume jaume     402 Jun  1 16:29 music.el
lrwxrwxrwx  1 jaume jaume      81 Jun  1 17:20 music.org -> /gnu/store/h41bhagak5ghkqam80rpxsz6qznnpril-home-dotfiles--config-emacs-music-org

I never experienced this behaviour before moving to a guix-managed home config…

I’m not exactly sure what you are trying to do, since I haven’t really used a literate configuration in a while, but each time you run guix home reconfigure you are creating a new generation of dotfiles, to which you can rollback to. If you make any changes you should run guix home reconfigure to apply them & generate the new files.

Hi @thanosapollo . Yes, I run guix home reconfigure to reapply the changes.

Literate config, via babel, ‘tangles’ all the org code blocks in the same org file into a single el file. The el file is the actual loaded file in emacs. So the configuration loop I am seeking is:

  1. Modify the emacs org files in my ~/src/me/dotfiles repo directory.
  2. Run guix home reconfigure to build a new generation that will symlink the org files into the ~/.config/emacs directory.
  3. Run emacs. → This step is the one that generates the new el files, before loading them and apply the new config.

The last step is the one it fails. It doesn’t “re-tangle” them, it loads previous el files.

Maybe my structure is wrong, maybe the whole configuration loop is stupid… IDK :person_shrugging:

You can do emacs config using the below org-files method to make it an org file for better looking.

For Guix config, I am not aware of any ready to use solution. However, it should not be hard to achieve because what you really need is to output org-scheme-block to guile file for guix.

Hmm… Maybe use something like auto-tangle to create .el files or directly tangle the contents of the files into your init.el & exclude *.org from home-dotfiles-configuration?

I personally just have a init.el file for my emacs config, which imenu makes it quite easy to navigate

I’ve ended up doing what you suggest (have a single init.el) and got rid of my literate config. At the end, literate config doesn’t bring any better behaviour.

I’ll probably split it again in different .el files because my current init.el file is too long for my taste… or fight again with literate config, but now I prefer to focus in other battles in my Guix journey.

Thanks for your help, @thanosapollo and @wxie !