Skip to content

Instantly share code, notes, and snippets.

@frondeus
Last active February 19, 2019 15:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frondeus/d92b3648a87fdebf2a2af2f58989ec84 to your computer and use it in GitHub Desktop.
Save frondeus/d92b3648a87fdebf2a2af2f58989ec84 to your computer and use it in GitHub Desktop.

Tangle init.org to init.el my way

To see tags usage please click Raw button.

Why?

I like Emacs. I like working using Emacs. And I have many workstations. I have my personal Macbook, and I have Dell with Windows 10 at work with cyngwin and with linux inside virtualbox.

And I was sick of juggling different versions of init.el / init.org.

How?

I wanted one, simple solution where I could choose which parts of my config are loaded on specific system. But I didn’t want to abuse system-type checking. I could use something like:

(use-package foo :if (eq system-type 'darwin))

But this runtime checking felt bad.

Org-Mode.

I love idea of literate programming, so naturally I used init.org with tangle combo.

For months I used this:

(defun frondeus/reload-and-tangle-init-org()
    "Reloads and tangles Emacs config."
    (interactive)
    (when (string= buffer-file-name (file-truename (concat user-emacs-directory "init.org")))
      (org-babel-tangle)
      (byte-compile-file (concat user-emacs-directory "init.el"))
      (byte-compile-file (concat user-emacs-directory "windows.el"))
      (byte-compile-file (concat user-emacs-directory "osx.el"))
      (load (concat user-emacs-directory "init"))))   

As you can see I had different files for systems with one shared config inside init.el. I used simple fact, that every heading can have own :tangle property. Then I had one system-type check to choose which file should be loaded.

Not enough - why should I compile osx.el if I wouldn’t load it on windows?

Then one day I came across this simple solution. And I knew I could refactor it to fit my idea.

Tags - that’s my solution. Simple and clean.

Example

If I want to tangle some shared config I just write #+BEGIN_SRC without any tag. Like that:

(use-package magit :ensure t)

But if I want to have some config only for cyngwin… I use tag like :cyngwin:

This config will be tangled only on my Dell.

(use-package omnisharp :ensure t)

I can have many tags like :linux:cyngwin: !

This config will be available on linux and cyngwin but not on osx.

(setq user-mail-address "my-email@email.com")

I can also disable some config by using :notangle: tag.

;; Old stuff....
(defun frondeus/reload-init-org()
"It reloads Emacs init config."
(interactive)
(load (concat user-emacs-directory "init")))
(defvar frondeus/tangle-tag-sys-list '(("osx" . "darwin")
("cyngwin" . "cyngwin")
("linux" . "gnu/linux")) "List of org mode tags and system-types.")
;; Highly based on http://www.holgerschurig.de/en/emacs-init-tangle/
(defun frondeus/tangle-init-org()
"It tangles Emacs init config from init.org to init.el and then compiles to init.elc."
(interactive)
(require 'org)
(message "*** Tangle init org")
(let* (
(body-list ())
(input-file (concat user-emacs-directory "init.org"))
(output-file (concat user-emacs-directory "init.el"))
(org-babel-default-header-args
(org-babel-merge-params org-babel-default-header-args
(list (cons :tangle output-file)))))
(message "Writing %s ..." output-file)
(save-restriction
(save-excursion
(org-babel-map-src-blocks input-file
(let* ((info (org-babel-get-src-block-info 'light))
(tfile (cdr (assq :tangle (nth 2 info))))
(tags)
(wrong-system nil))
(save-excursion
(catch 'exit
(setq tags (org-get-local-tags))))
(dolist (tag-sys frondeus/tangle-tag-sys-list)
(let* ((tag (car tag-sys)) (sys (cdr tag-sys)))
(unless (null (member tag tags))
(setq wrong-system t))
(when (string= sys system-type) (setq wrong-system nil))))
(when (and (not(string= "no" tfile))
(null wrong-system)
(null (member "notangle" tags))
(string= "emacs-lisp" lang))
(add-to-list 'body-list body)))))
(with-temp-file output-file
(insert (apply 'concat (reverse body-list))))
(message "Wrote %s ..." output-file))
(byte-compile-file output-file)))
(defun frondeus/reload-and-tangle-init-org()
"It reloads and tangles Emacs init config."
(when (string= buffer-file-name (file-truename (concat user-emacs-directory "init.org")))
(frondeus/tangle-init-org)
(frondeus/reload-init-org)))
(add-hook 'after-save-hook 'frondeus/reload-and-tangle-init-org)
@frondeus
Copy link
Author

I know my english and my elisp skills are not perfect. If you see I made mistake - please give me feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment