56

My .emacs configuration file gets bigger and bigger and I'd like to get a better overview and structuring by adding headings, subheadings and being able to hide or show them like I can do with Emacs org-mode.

I noticed that I can activate org-mode also in the .emacs buffer and that it is possible to add headings and collapse them. But will Emacs/Aquamacs still be able to load the Elisp code from the document if I add org-mode headings (i.e., lines starting with one or more asterisks)?

Can I have all that in one file or would I have to have one .*org file and then regularly export the Elisp code to another file?

6 Answers 6

54

Yes, you certainly can, you can use org-babel-load-file to do this.

In your init.el, put the following:

(require 'org)
(org-babel-load-file
 (expand-file-name "settings.org"
                   user-emacs-directory))

(I'm using ~/.emacs.d/settings.org but that is personal preference). In the settings.org file you can arrange it however you would like, wrapping elisp in:

* Turn off menu bar
#+BEGIN_SRC emacs-lisp
(menu-bar-mode -1)
#+END_SRC

When you start Emacs, it will automatically determine if the settings.org file has changed, and if needed, tangle it to produce a settings.el file which will be loaded.

7
  • 1
    How would you change this to load the latest org from elpa, instead of the org that is available in a clean emacs? It seems the package initialization code would need to be pulled out of settings.org and put into init.el?
    – mankoff
    Commented Nov 5, 2014 at 15:18
  • 4
    @mankoff That's correct, this is my init.el: (require 'package) (package-initialize) (setq custom-file "~/.emacs.d/custom.el") (when (file-exists-p custom-file) (load custom-file)) (require 'org) (org-babel-load-file (expand-file-name "settings.org" user-emacs-directory))
    – Lee H
    Commented Nov 5, 2014 at 15:23
  • 3
    @mankoff Sorry for the poor formatting, I have a more readable version near the top of writequit.org/org/settings.html
    – Lee H
    Commented Nov 5, 2014 at 15:27
  • 2
    There are more than a few examples of literate Emacs configs. Perhaps it is time to start an index. Here is mine for example github.com/grettke/home
    – grettke
    Commented Jan 12, 2015 at 22:40
  • 1
    remember not to configure org related stuff inside the org file if you want to use the latest version of org (9) available on Melpa. I am doing this github.com/cescoferraro/dotfiles/blob/master/src/emacs.d/…
    – CESCO
    Commented Apr 5, 2017 at 16:29
27

If all you want is selective showing of sections and navigation between headings, you don't need Org mode. All you need is Outline mode. Outline mode is basically the header level and section visibility management of Org mode. In fact, Org mode was originally the author's extensions to Outline mode, and grew, and grew, and grew… Even today, org-mode is derived from outline-mode.

Outline mode exists both as a major mode and as a minor mode. The minor mode can be used in any major mode. You can configure it to use a header format that's compatible with your program syntax, and many major modes do so, by setting the outline-regexp variable to a regexp that matches the start of a header. For example, this is the default value in Emacs Lisp mode:

";;;\\(;* [^ \t\n]\\|###autoload\\)\\|("

i.e. section headers start with three or more semicolons and a single space, or an opening parenthesis in the left margin. The variable outline-level contains the name of a function to determine the depth of a header; the default value is the length of the string matched by outline-regexp, and Emacs Lisp mode overrides it to assign a larger depth to ( and ;;;###autoload.

If you don't like the default header format, set the variable outline-regexp in a file local variable declaration. This is what I use — my section headers all consists of ;;; followed by the classic sequence of stars:

;;; Local Variables:
;;; outline-regexp: ";;;\\*+\\|\\`"
;;; End:

If you want Outline minor mode to be automatically turned on when you load the file, add the following line in the Local Variables section — note that this will warn you about unsafe code in Emacs ≤23.x.

;;; eval: (outline-minor-mode 1)

The commands for outline minor mode use the rather inconvenient C-c @ prefix by default. I move it to M-o (I never use the facemenu bindings), you may prefer another key, or to replicate Org mode's bindings (which have diverged quite a bit from Outline mode).

3
  • 5
    I second this. Org is great, but for this, all you need is outline-mode. And it gets even better if you combine it with outshine-mode, outorg, and navi-mode. With outshine and outorg, you don't need to use org-babel and its tangling into separate files to get nice org-mode-style comments. Here is a gist of the elisp code I use to make Python, elisp, and shell code work and fold nicely in outline/outshine.
    – user3871
    Commented Mar 22, 2015 at 8:26
  • How would one open the file nested?
    – Edman
    Commented Jan 9, 2021 at 10:10
  • 10 years later ... this works very well for me, so thanks for posting here. One thing I don't understand is the significance of the \\|\\' in outline-regexp. In the emacs manual, ` matches an empty string at the start of the pattern. Whatever - outline-regexp does not work without it! I'd just like to understand the reason.
    – wef
    Commented Mar 25, 2023 at 7:07
14

Literate programming takes you the most way there, org-mode supports it via org-babel. Two possible solutions are explained on @malabarba's blog:

The simplest way is loading org-mode, then using its untangling feature to load a literate Emacs configuration:

(require 'org)
(org-babel-load-file
 (expand-file-name "emacs-init.org"
                   user-emacs-directory))

Alternatively (to avoid loading org entirely), untangling can be done with the Emacs Lisp primitives:

(defvar endless/init.org-message-depth 3
  "What depth of init.org headers to message at startup.")

(with-temp-buffer
  (insert-file "~/.emacs.d/init.org")
  (goto-char (point-min))
  (search-forward "\n* init.el")
  (while (not (eobp))
    (forward-line 1)
    (cond
     ;; Report Headers
     ((looking-at
       (format "\\*\\{2,%s\\} +.*$"
               endless/init.org-message-depth))
      (message "%s" (match-string 0)))
     ;; Evaluate Code Blocks
     ((looking-at "^#\\+BEGIN_SRC +emacs-lisp.*$")
      (let ((l (match-end 0)))
        (search-forward "\n#+END_SRC")
        (eval-region l (match-beginning 0))))
     ;; Finish on the next level-1 header
     ((looking-at "^\\* ")
      (goto-char (point-max))))))
9

One more vote for outline-mode. For example for organaizing .emacs I use the following syntax:

;;; HEADING:

the important parts are ;;; and :\n

(add-hook 'emacs-lisp-mode-hook 
          (lambda ()
            (make-local-variable 'outline-regexp)
            (setq outline-regexp "^;;; ")
            (make-local-variable 'outline-heading-end-regexp)
            (setq outline-heading-end-regexp ":\n")
            (outline-minor-mode 1)
            ))

Here's a sample .emacs:

;;; preliminaries:
;; load-path:
;; This little monster adds all non-dot dirs to Your load path recursively
(let* ((my-lisp-dir "~/.emacs.d/site-lisp/")
       (default-directory my-lisp-dir)
       (orig-load-path load-path))
  (setq load-path (cons my-lisp-dir nil))
  (normal-top-level-add-subdirs-to-load-path)
  (nconc load-path orig-load-path))

;; ...

;;; modes:

;; python-mode:
(setq py-install-directory "~/.emacs.d/site-lisp/python-mode")
(add-to-list 'load-path py-install-directory)
(require 'python-mode)

;; ...

;;; customizations:
(custom-set-variables
 '(blink-cursor-mode nil)
)

;; ...

One should enable outline-minor-mode and then the two required key strokes are:

  • C-c @ C-t — show top level structure

    the above becomes

    ;;; preliminaries:
    ;;; modes:
    ;;; customizations:
    
  • C-c @ C-a — show all again

A typical usage is to show top level structure, move to the heading of interest, and showing all again.

3
  • 1
    can we use directives like in org-mode: e.g. #+STARTUP: overview or show all or contents options.
    – doctorate
    Commented Mar 18, 2016 at 12:42
  • @doctorate: org-mode support for folding is also built on top of outline-mode. We can't use just the directives: because in contrast to org-mode -- in elisp # is not a comment sign, so emacs' built-in elisp interpreter would be confused when it hit the #+STARTUP or something like this. (or have I misunderstood you comment?)
    – Adobe
    Commented Mar 18, 2016 at 15:22
  • I mean is there a way to implement the STARTUP directive inside orgstruct-mode, for example this was an R buffer but the same idea: emacs.stackexchange.com/a/8065/2443
    – doctorate
    Commented Mar 18, 2016 at 18:06
4

On the following SO answer you will see how to do it, example projects using one single org file or many, what's the benefit of using Cask and links to documentation.

https://stackoverflow.com/questions/25430029/whats-the-best-way-to-package-my-emacs-installation-packages-and-config-so-tha/25430745#25430745

I turned my config to org a few months ago, and I am not totally satisfied with it. It requires some config and reading of the org manual to have a useful org file that makes it easy to edit elisp code. One has to enable src block fontifying (off by default -> use a per-file variable), check that other modes don't conflict for editing src blocks (auto-fill mode), etc. One doesn't want to use C-c (backtick) (org-edit-src-block`) to edit a src block. And it gets a little bit in the way for debug.

My advice would be: start by breaking your init file into small elisp pieces, try some narrowing package out there, use helm-swoop for quick navigation, and then consider using org-mode.

1

I have recently invested some time to do exactly that. I have ended up with a configuration that - is maintained with org-mode - uses 'use-package' to auto-install missing packages - is a github repo that kind of auto-installs (shameless plug: https://github.com/pascalfleury/emacs-config)

I have 'bootstrapped' a few machines (Linux and Mac) by cloning the repo and adding a single line in the ~/.emacs et voila. I'm setup as I like.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.