55

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?

MostlyHarmless
  • 1,395
  • 2
  • 13
  • 14

6 Answers6

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.

Lee H
  • 2,697
  • 1
  • 16
  • 31
  • 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 Nov 05 '14 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 Nov 05 '14 at 15:23
  • 3
    @mankoff Sorry for the poor formatting, I have a more readable version near the top of http://writequit.org/org/settings.html – Lee H Nov 05 '14 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 https://github.com/grettke/home – grettke Jan 12 '15 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 https://github.com/cescoferraro/dotfiles/blob/master/src/emacs.d/init.el – CESCO Apr 05 '17 at 16:29
  • @CESCO I don't understand. Why not to configure org related stuff in the org file? Please explain. – Refael Sheinker Apr 30 '23 at 21:33
  • @mankoff I don't understand your comment. Can you please explain? – Refael Sheinker Apr 30 '23 at 21:35
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).

  • 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](https://gist.github.com/alphapapa/0f76ffe9792fffecb017) is a gist of the elisp code I use to make Python, elisp, and shell code work and fold nicely in outline/outshine. –  Mar 22 '15 at 08:26
  • How would one open the file nested? – Edman Jan 09 '21 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 Mar 25 '23 at 07: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))))))
wasamasa
  • 21,803
  • 1
  • 65
  • 97
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.

Adobe
  • 1,859
  • 13
  • 27
  • 1
    can we use directives like in org-mode: e.g. `#+STARTUP: overview` or `show all` or `contents` options. – doctorate Mar 18 '16 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 Mar 18 '16 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: http://emacs.stackexchange.com/a/8065/2443 – doctorate Mar 18 '16 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.

Ehvince
  • 1,091
  • 10
  • 14
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.

paf
  • 11
  • 1