summaryrefslogtreecommitdiff
path: root/init.org
blob: 5c00846a5fb209be6ae470b5abeadddd2bbadfa9 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
#+Title: Emacs Customizations
#+Author: Ricardo Wurmus

#+PROPERTY: noweb tangle
#+PROPERTY: mkdirp t
#+OPTIONS: tasks:nil toc:1

* Introduction

My Emacs configuration is a mess.  As I’m writing this my Emacs
configuration stretches across multiple files, each containing various
snippets of code that seemed like a good idea to group.

Unfortunately, there are a some things that don’t have a “natural”
home.  Enabling the same minor mode in various major modes is one of
these cases—do I duplicate the hook and place it in a file for each
major mode?  Or do I write a new file for the minor mode in which I
add it to the major modes at once?

With multiple files I spend too much time trying to find the best
place for any bit of configuration I add.  This slows me down and
sometimes I just append to the main =init.el=, so I often feel that my
configuration is in need of reorganisation.  But configuring Emacs
should be fun!  I don’t want it to create an uncomfortable clean-up
task as a side-effect.  This is why I’m now trying to use a literate
approach with =org-mode=.  My Emacs configuration should be prose
first and code second.  In my experience, finding the right spot in
prose for a new paragraph requires a lot less effort as the text
itself acts as a connection between unrelated bits of code.

* How to use this?

The sole purpose of the =~/.emacs.d/init.el= file is now to load up
and interpret this =org-mode= file.  (We don’t execute this code
here.)

#+BEGIN_SRC elisp :tangle no
(require 'org)

;; Load the actual configuration file
(org-babel-load-file
  (expand-file-name (concat user-emacs-directory "init.org")))
#+END_SRC

Alternatively, we can take all code blocks in this file and assemble
an =init.el= from it.  This is what the =org-babel-tangle= procedure
does for us.  I actually prefer doing it this way, because startup
times are faster this way as org-mode doesn’t have to be loaded first.
We can even byte-compile the init file.

* Initialise packages
:PROPERTIES:
:noweb-ref: packages
:END:

Emacs is an operating system and I use it as such (see [[http://elephly.net/posts/2016-02-14-ilovefs-emacs.html][this blog
post]]).  I rely on quite a few extensions that have been made available
on various ELPA repositories.  Recently, I have moved to installing
and managing Emacs packages like any other software package on my
system with the functional package manager [[https://gnu.org/s/guix][GNU Guix]].  I find this more
reliable, although at first it is slightly less convenient as I can no
longer just use =package.el= but first need to package the Elisp code
for Guix.

To install all packages via GNU Guix I can either use a manifest file
or use the following invocation:

#+BEGIN_SRC bash :noweb-ref nil
  guix package -i \
    emacs \
    emacs-auctex \
    emacs-better-defaults \
    emacs-clojure-mode \
    emacs-company \
    emacs-debbugs \
    emacs-emms \
    emacs-god-mode \
    emacs-haskell-mode \
    emacs-ido-ubiquitous \
    emacs-js2-mode \
    emacs-lispy \
    emacs-markdown-mode \
    emacs-mmm-mode \
    emacs-multiple-cursors \
    emacs-org-bullets \
    emacs-pdf-tools \
    emacs-projectile \
    emacs-smex \
    emacs-typo \
    emacs-undo-tree \
    emacs-web-mode \
    emacs-wget \
    emacs-zenburn-theme \
    paredit \
    geiser \
    magit \
    sicp \
#+END_SRC

There are some packages I use that are not yet packaged for Guix.
Here’s a list of them:

#+BEGIN_SRC elisp
(defvar my/packages
  '(centered-cursor-mode
    org-beautify-theme
    erc-hl-nicks
    expand-region
    fill-column-indicator
    guide-key
    hungry-delete
    ido-vertical-mode
    page-break-lines
    paren-face
    perspective
    rich-minority
    scss-mode
    shell-switcher
    skewer-mode
    smart-mode-line
    sublime-themes
    tagedit
    visual-regexp-steroids
    znc))
#+END_SRC

I want these packages to be installed automatically.  First I need to
define in what repositories Emacs should look for the packages.  I’m
using packages from both the “melpa” and “marmalade” repositories.

#+BEGIN_SRC elisp
(require 'package)
(add-to-list 'package-archives
             '("melpa"     . "http://melpa.milkbox.net/packages/"))
(add-to-list 'package-archives
             '("marmalade" . "http://marmalade-repo.org/packages/"))
(package-initialize)
#+END_SRC

If this is a fresh Emacs installation melpa needs to be initialised
first:

#+BEGIN_SRC elisp
(unless (file-exists-p "~/.emacs.d/elpa/archives/melpa")
  (package-refresh-contents))
#+END_SRC

Now we are ready to install packages if they aren’t yet installed.

#+BEGIN_SRC elisp
(defun packages-install (packages)
  (mapcar (lambda (package)
            (when (not (package-installed-p package))
              (package-install package)))
          packages)
  (delete-other-windows))

(defun init--install-packages ()
  (packages-install my/packages))
#+END_SRC

Install packages as soon as this configuration is evaluated.  If
there’s an error (e.g. because a package by this name cannot be found)
ask Emacs to refresh the list of packages and retry.  If there’s an
error again we just ignore it.  It could be that it’s because there’s
no Internet connection.

#+BEGIN_SRC elisp
(condition-case e
    (init--install-packages)
  (error
   (ignore-errors
     (package-refresh-contents)
     (init--install-packages))))
#+END_SRC

* Default fonts
:PROPERTIES:
:noweb-ref: default-fonts
:END:

I like pretty faces.  For coding I like to use the DejaVu Sans Mono
font.  In =org-mode= and in =eww= I like to use a font with variable
pitch instead of the default mono-spaced font.  I find Linux Biolinum
pretty, especially when it’s rendered large.

#+BEGIN_SRC elisp
(set-default-font "DejaVu Sans Mono")
(set-face-attribute 'variable-pitch nil :height 1.3 :family "Linux Biolinum")
#+END_SRC

* TODO Org-mode
This is my org mode configuration.  Document it.

#+BEGIN_SRC elisp :noweb-ref org-mode-part1
(setq org-ellipsis "⤵")
(setq org-src-fontify-natively t)

(global-set-key (kbd "C-c o l") 'org-store-link)
(global-set-key (kbd "C-c o a") 'org-agenda)

;; TODO: make these available in org-mode only
(global-set-key (kbd "C-c o s") 'org-schedule)
(global-set-key (kbd "C-c o c") 'org-capture)

(setq org-log-done t)
(setq org-return-follows-link t)

(setq org-directory "~/Documents/org")
(setq org-agenda-files (mapcar (lambda (x) (concat org-directory x))
                               (list "/master.org"
                                     "/work.org"
                                     "/study.org"
                                     "/home.org")))
(setq org-default-notes-file (concat org-directory "/notes.org"))

(setq org-agenda-custom-commands
      '(("w" todo "WAITING" nil)
        ("n" todo "NEXT" nil)
        ("d" "Agenda + Next Actions" ((agenda) (todo "NEXT")))))

(defun my/modify-org-done-face ()
  (setq org-fontify-done-headline t)
  (set-face-attribute 'org-done nil :strike-through t)
  (set-face-attribute 'org-headline-done nil
                      :strike-through t
                      :foreground "light gray"))

(require 'org-bullets)
(add-hook 'org-add-hook 'my/modify-org-done-face)
(add-hook 'org-mode-hook
          (lambda ()
            (org-bullets-mode 1)

            ;; render with variable pitch font (with a few exceptions)
            (variable-pitch-mode 1)
            (dolist (face '(org-block-begin-line
                            org-block-end-line
                            org-table
                            org-verbatim
                            org-block-background))
              (set-face-attribute face nil :inherit 'fixed-pitch))))

(defun gtd ()
  (interactive)
  (find-file (concat org-directory "/master.org")))
#+END_SRC

The following snippet is an attempt to prettify the somewhat ugly
headers of source code blocks in =org-mode=.  The snippet was taken
from [[https://pank.eu/blog/pretty-babel-src-blocks.html][the blog of Rasmus Pank]] and slightly modified to suit my needs.

#+BEGIN_SRC elisp :noweb-ref org-mode-pretty
(defvar-local rasmus/org-at-src-begin -1
  "Variable that holds whether last position was a ")

(defvar rasmus/ob-header-symbol ?☰
  "Symbol used for babel headers")

(defun rasmus/org-prettify-src--update ()
  (let ((case-fold-search t)
        (re "^[ \t]*#\\+begin_src[ \t]+[^ \f\t\n\r\v]+[ \t]*")
        found)
    (save-excursion
      (goto-char (point-min))
      (while (re-search-forward re nil t)
        (goto-char (match-end 0))
        (let ((args (org-trim
                     (buffer-substring-no-properties (point)
                                                     (line-end-position)))))
          (when (org-string-nw-p args)
            (let ((new-cell (cons args rasmus/ob-header-symbol)))
              (cl-pushnew new-cell prettify-symbols-alist :test #'equal)
              (cl-pushnew new-cell found :test #'equal)))))
      (setq prettify-symbols-alist
            (cl-set-difference prettify-symbols-alist
                               (cl-set-difference
                                (cl-remove-if-not
                                 (lambda (elm)
                                   (eq (cdr elm) rasmus/ob-header-symbol))
                                 prettify-symbols-alist)
                                found :test #'equal)))
      ;; Clean up old font-lock-keywords.
      (font-lock-remove-keywords nil prettify-symbols--keywords)
      (setq prettify-symbols--keywords (prettify-symbols--make-keywords))
      (font-lock-add-keywords nil prettify-symbols--keywords)
      (while (re-search-forward re nil t)
        (font-lock-flush (line-beginning-position) (line-end-position))))))

(defun rasmus/org-prettify-src ()
  "Hide src options via `prettify-symbols-mode'.

`prettify-symbols-mode' is used because it has uncollpasing. It's
may not be efficient."
  (let* ((case-fold-search t)
         (at-src-block (save-excursion
                         (beginning-of-line)
                         (looking-at "^[ \t]*#\\+begin_src[ \t]+[^ \f\t\n\r\v]+[ \t]*"))))
    ;; Test if we moved out of a block.
    (when (or (and rasmus/org-at-src-begin
                   (not at-src-block))
              ;; File was just opened.
              (eq rasmus/org-at-src-begin -1))
      (rasmus/org-prettify-src--update))
    ;; Remove composition if at line; doesn't work properly.
    ;; (when at-src-block
    ;;   (with-silent-modifications
    ;;     (remove-text-properties (match-end 0)
    ;;                             (1+ (line-end-position))
    ;;                             '(composition))))
    (setq rasmus/org-at-src-begin at-src-block)))

(defun rasmus/org-prettify-symbols ()
  (mapc (apply-partially 'add-to-list 'prettify-symbols-alist)
        (cl-reduce 'append
                   (mapcar (lambda (x) (list x (cons (upcase (car x)) (cdr x))))
                           `(("#+begin_src" . ?✎) ;; ➤ 🖝 ➟ ➤ ✎
                             ("#+end_src"   . ?□) ;; ⏹
                             ("#+header:" . ,rasmus/ob-header-symbol)
                             ("#+begin_quote" . ?»)
                             ("#+end_quote" . ?«)))))
  (turn-on-prettify-symbols-mode)
  (add-hook 'post-command-hook 'rasmus/org-prettify-src t t))
(add-hook 'org-mode-hook #'rasmus/org-prettify-symbols)
#+END_SRC

All of this should be loaded lazily.

#+BEGIN_SRC elisp :noweb-ref org-mode
(provide 'my/init-org)
(with-eval-after-load "org"
  <<org-mode-part1>>
  <<org-mode-pretty>>
  )
(require 'org)
#+END_SRC

* TODO Initial stuff
:PROPERTIES:
:noweb-ref: initial
:END:

This is supposed to happen at the very beginning, even before loading
packages.  I still need to arrange these things nicely.

#+BEGIN_SRC elisp
;; No splash screen please ...
(setq inhibit-startup-message t)

;; FIXME: This is needed to be able to use IBus Pinyin with Emacs
(setenv "LC_CTYPE" "zh_CN.utf8")

;; display tool tips in echo area only
(tooltip-mode -1)
(setq frame-resize-pixelwise t)
(defalias 'yes-or-no-p 'y-or-n-p)

;; disable mouse scrolling
(mouse-wheel-mode -1)

(add-to-list 'load-path (concat user-emacs-directory "lisp"))
#+END_SRC

* TODO More stuff
:PROPERTIES:
:noweb-ref: initial-after-packages
:END:

This is even more stuff to be done after initialising packages.  I
still need to process all of this and clean it up.

#+BEGIN_SRC elisp
;; better defaults, includes hiding the GUI
(require 'better-defaults)
(require 'paren-face)
(global-paren-face-mode 1)
(require 'paren)
(setq show-paren-delay 0)
(show-paren-mode 1)

(require 'projectile)
(projectile-global-mode)

(require 'guide-key)
(setq guide-key/guide-key-sequence '("C-x r" "C-x 4" "C-c p"))
(guide-key-mode)

;; Keep emacs Custom-settings in separate file
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(load custom-file)

(setq frame-background-mode 'light)
(load-theme 'solarized t)

(add-hook 'haskell-mode-hook
          (lambda ()
            (turn-on-haskell-indentation)
            (turn-on-haskell-doc)))
#+END_SRC

* Putting it all together

Having defined named code blocks in the sections above we can finally
put them all together to build the init file

#+BEGIN_SRC elisp :noweb yes :tangle "~/.emacs.d/init.el"
<<initial>>
<<packages>>
<<default-fonts>>
<<initial-after-packages>>
<<org-mode>>
(load "~/.emacs.d/old-init.el")
#+END_SRC


# Local Variables:
# org-edit-src-content-indentation: 0
# eval: (add-hook 'org-babel-post-tangle-hook (lambda nil (byte-compile-file "~/.emacs.d/init.el")))
# End: