summaryrefslogtreecommitdiff
path: root/init.org
blob: 7e238933ce796f0fba9ca7b910af927d6a229333 (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
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
#+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?
:PROPERTIES:
:noweb-ref: compile-init
:END:

We take all code blocks in this file and assemble an =init.el= from it if the source file =init.org= is younger.  At startup time we check if the =init.el= has to be regenerated.

#+BEGIN_SRC elisp
(let ((orgfile (expand-file-name (concat user-emacs-directory "init.org")))
      (target  (expand-file-name (concat user-emacs-directory "init.el"))))
  (when (not (file-newer-than-file-p target orgfile))
    (progn
      (require 'org)
      (org-babel-tangle-file orgfile)
      (byte-compile-file target)
      (load target))))
#+END_SRC

* 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 sh :noweb-ref nil
  guix package -i \
    emacs \
    emacs-auctex \
    emacs-better-defaults \
    emacs-clojure-mode \
    emacs-company \
    emacs-debbugs \
    emacs-emms \
    emacs-emms-mode-line-cycle \
    emacs-emms-player-mpv \
    emacs-ess \
    emacs-expand-region \
    emacs-fill-column-indicator \
    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-page-break-lines \
    emacs-paren-face \
    emacs-pdf-tools \
    emacs-perspective \
    emacs-projectile \
    emacs-rich-minority \
    emacs-shell-switcher \
    emacs-solarized-theme \
    emacs-skewer-mode \
    emacs-smart-mode-line \
    emacs-smex \
    emacs-tagedit \
    emacs-typo \
    emacs-undo-tree \
    emacs-web-mode \
    emacs-wget \
    emacs-zenburn-theme \
    emacs-znc \
    emacs-paredit \
    emacs-geiser \
    emacs-magit \
    emacs-sicp \
    mu
#+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
    guide-key
    ido-vertical-mode
    scss-mode))
#+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)
  (mapc (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-frame-font "DejaVu Sans Mono")
(set-face-attribute 'variable-pitch nil :height 1.25 :family "Linux Biolinum")
#+END_SRC

* Manuals
:PROPERTIES:
:noweb-ref: manuals
:END:

Also in Info manuals I want to use variable-pitch fonts where possible.  Unfortunately, Info manuals don’t contain enough semantic markup, so I cannot selectively use a monospace font for examples or inline code and use a variable pitch font for everything else.  So I just use variable pitch in headings.

#+BEGIN_SRC elisp
(require 'info)
(set-face-attribute 'info-title-1 nil
  :inherit 'variable-pitch
  :height 1.3)
(set-face-attribute 'info-title-2 nil
  :inherit 'variable-pitch
  :height 1.3)
(set-face-attribute 'info-title-3 nil
  :inherit 'variable-pitch
  :height 1.3)
(set-face-attribute 'info-menu-header nil
  :inherit 'variable-pitch
  :height 1.1)
#+END_SRC

Since Emacs 25 there is a new face for quoted expressions in Info manuals.  By default it uses the “courier” font, which looks terrible.

#+BEGIN_SRC elisp
(set-face-attribute 'Info-quoted nil
  :inherit 'fixed-pitch
  :family "Monospace")
#+END_SRC

* Org-mode
:PROPERTIES:
:noweb-ref: org-mode
:END:

This is my org mode configuration.  Document it.

#+BEGIN_SRC elisp
(require 'org-indent)
(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)

(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"
                                     "/email.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")))))

(setq org-fontify-done-headline t)

(require 'org-bullets)
(setq org-bullets-bullet-list '("◉" "○" "◇" "◇"))
(add-hook 'org-mode-hook
          (lambda ()
            (org-bullets-mode 1)
            (variable-pitch-mode 1)
            (visual-line-mode 1)))

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


I don’t like the way org-mode looks by default.  It’s noisy, too colourful and seems old-fashioned to the point of being somewhat unattractive.  This is why I find it important to change some of the default faces.

Since I enable =variable-pitch-mode= in my org-mode buffers I also need to explicitly make a few faces inherit from the =fixed-width= face to be rendered with a monospaced font.

#+BEGIN_SRC elisp
(set-face-attribute 'org-done nil :strike-through t)
(set-face-attribute 'org-headline-done nil
                    :strike-through t
                    :foreground "light gray")
(set-face-attribute 'org-document-title nil
  :height 1.6
  :foreground "#073642")
(set-face-attribute 'org-level-1 nil
  :height 1.0
  :foreground "#586e75")
(set-face-attribute 'org-level-2 nil
  :height 0.9
  :foreground (face-attribute 'default :foreground))
(set-face-attribute 'org-level-3 nil
  :height 0.8
  :foreground (face-attribute 'default :foreground))
(set-face-attribute 'org-level-4 nil
  :height 0.8
  :foreground (face-attribute 'default :foreground))
(set-face-attribute 'org-block-background nil :background "#efe9d6")
(set-face-attribute 'org-verbatim nil :background "#efe9d6")
(dolist (face '(org-meta-line
                org-document-info-keyword
                org-special-keyword))
(set-face-attribute face nil :foreground "#93a1a1"
                             :weight 'normal))
(dolist (face '(org-block-begin-line
                org-block-end-line
                org-block
                org-table
                org-meta-line
                org-document-info-keyword
                org-special-keyword
                org-verbatim
                org-todo
                org-tag
                org-done
                org-hide
                org-indent
                org-checkbox
                org-block-background))
  (set-face-attribute face nil :inherit 'fixed-pitch)
  ;; TODO: this is ugly.  When scaling up the variable-pitch face the
  ;; fixed-pitch face will become even larger.
  (set-face-attribute face nil :height 0.8))

(set-face-attribute 'org-tag nil
                    :foreground (face-attribute 'default :foreground)
                    :weight 'normal
                    :height (face-attribute 'default :height)
                    :overline nil
                    :underline nil
                    :box '(:line-width -1 :color "#859900"))
#+END_SRC

To ensure that indented blocks line up with their headings despite using =variable-pitch-mode= we set the indentation character to =*= and hide it by setting the foreground colour to the same as the default background colour.

#+BEGIN_SRC elisp
(setq org-indent-boundary-char ?*)
(set-face-attribute 'org-indent nil :foreground  (face-attribute 'default :background))
#+END_SRC

=variable-pitch-mode= also makes it impossible to align tags at a fixed column, so I don’t.  Instead I just let tags appear right behind the heading.

#+BEGIN_SRC elisp
(setq org-tags-column 0)
#+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
(defvar-local my/org-at-src-begin -1
  "Variable that holds whether last position was an org source code block.")

(defvar-local my/org-src-begin-regexp
  "^[ \t]*#\\+begin_src[ \t]+[^ \f\t\n\r\v]+[ \t]*")

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

(defun my/org-prettify-src--update ()
  (let ((case-fold-search t)
        (re my/org-src-begin-regexp)
        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 my/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) my/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)))
      ;; Toggle prettify-symbols-mode to restore composition of
      ;; regions on which the "composition" text-property was deleted.
      (prettify-symbols-mode -1)
      (prettify-symbols-mode +1))))

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

`prettify-symbols-mode' is used because expanding is simple.  It’s
not very efficient and maybe should be implemented using overlays."
  (let* ((case-fold-search t)
         (at-src-block (save-excursion
                         (beginning-of-line)
                         (looking-at my/org-src-begin-regexp))))
    ;; Test if we moved out of a block.
    (cond ((or (and my/org-at-src-begin
                     (not at-src-block))
                ;; File was just opened.
               (eq my/org-at-src-begin -1))
           (my/org-prettify-src--update))
          ;; Remove composition if at line
          (at-src-block
           (with-silent-modifications
             (remove-text-properties (match-end 0)
                                     (1+ (line-end-position))
                                     '(composition)))))
    (setq my/org-at-src-begin at-src-block)))

(defun my/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:" . ,my/ob-header-symbol)
                             ("#+begin_quote" . ?«)
                             ("#+end_quote" . ?»)))))
  (turn-on-prettify-symbols-mode)
  (add-hook 'post-command-hook 'my/org-prettify-src t t))
(add-hook 'org-mode-hook #'my/org-prettify-symbols)
#+END_SRC

I use the capture feature to quickly record ideas and tasks, and to create links to emails that I need to work on.  This is much better than just leaving these emails in my Inbox.

#+BEGIN_SRC elisp
(global-set-key (kbd "C-c o c") 'org-capture)
(setq org-capture-templates
      '(("t" "Task" entry
             (file+headline (concat org-directory "/home.org") "Tasks")
             "* %?\n  %i\n  %a")
        ("m" "Email" entry
             (file+headline (concat org-directory "/email.org") "Email")
             "* Reply to %:fromname%? :email:\n [%:date]\n To: %:to\n %a")))
#+END_SRC

For exporting org documents to PDF I use =lualatex= instead of the default =pdflatex=.  This requires me to change the value of =org-latex-pdf-process=.

#+BEGIN_SRC elisp
(setq org-latex-pdf-process
  '("lualatex -interaction nonstopmode -output-directory %o %f"
    "lualatex -interaction nonstopmode -output-directory %o %f"
    "lualatex -interaction nonstopmode -output-directory %o %f"))
#+END_SRC

All of this should be loaded lazily.

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

* Editing files on remote systems
:PROPERTIES:
:noweb-ref: tramp
:END:

TRAMP is a really convenient way to edit files on remote systems from within the comfort of my cozy customised local Emacs session.  I use it to edit files at work, to edit things on my server =elephly.net=, and even to edit things as root on the local system.

#+BEGIN_SRC elisp
(require 'tramp)
(setq tramp-default-method "ssh")

(setq tramp-default-proxies-alist
      (list
       ;; Do not use a proxy on the same system.
       '((regexp-quote (system-name)) nil nil)
       ;; For root connections to remote hosts, log in via ssh with normal
       ;; user account first, then su/sudo to root
       '("elephly\\.net\\'" "\\`root\\'" "/ssh:%h:")
       ;; Pass through ssh1 as user ‘rwurmus’ to reach remote hosts on
       ;; MDC network.
       '("mdc-berlin\\.net" "\\`rwurmus\\'" "/ssh:rwurmus@ssh1.mdc-berlin.de:")))

;; ssh1 runs a restricted shell session, so "exec ssh" cannot be used.
(add-to-list 'tramp-restricted-shell-hosts-alist
             "\\`ssh1\\.mdc-berlin\\.de\\'")

;; respect the PATH variable on the remote machine
(add-to-list 'tramp-remote-path 'tramp-own-remote-path)
(setq tramp-verbose 3)
#+END_SRC

* Shell
:PROPERTIES:
:noweb-ref: shell
:END:

The default prompt face makes it hard to see the prompt.

#+BEGIN_SRC elisp
(set-face-attribute 'comint-highlight-prompt nil
  :foreground "#859900"
  :weight 'bold)
#+END_SRC

* Magit
:PROPERTIES:
:noweb-ref: magit
:END:

#+BEGIN_SRC elisp
;; full screen magit-status
(defadvice magit-status (around magit-fullscreen activate)
  (window-configuration-to-register :magit-fullscreen)
  ad-do-it
  (delete-other-windows))

(defun my/magit-quit-session ()
  "Restores the previous window configuration and kills the magit buffer"
  (interactive)
  (kill-buffer)
  (jump-to-register :magit-fullscreen))

(defun my/magit-toggle-whitespace ()
  "Toggles git option -w"
  (interactive)
  (if (member "-w" magit-diff-options)
      (my/magit-dont-ignore-whitespace)
    (my/magit-ignore-whitespace)))

(defun my/magit-ignore-whitespace ()
  "Adds git option -w"
  (interactive)
  (add-to-list 'magit-diff-options "-w")
  (magit-refresh))

(defun my/magit-dont-ignore-whitespace ()
  "Removes git option -w"
  (interactive)
  (setq magit-diff-options (remove "-w" magit-diff-options))
  (magit-refresh))

(define-key magit-status-mode-map (kbd "q") 'my/magit-quit-session)
(define-key magit-status-mode-map (kbd "W") 'my/magit-toggle-whitespace)

(setq magit-diff-refine-hunk 'all)
#+END_SRC

#+BEGIN_SRC elisp :noweb-ref magit-lazy
(provide 'my/init-magit)
(with-eval-after-load "magit"
  <<magit>>
  )
(require 'magit)
(global-set-key (kbd "C-c m") 'magit-status)
#+END_SRC

* Ido
:PROPERTIES:
:noweb-ref: ido
:END:

#+BEGIN_SRC elisp
(require 'ido-vertical-mode)
(ido-mode 1)
(ido-vertical-mode 1)
(setq ido-vertical-define-keys 'C-n-and-C-p-only)
(setq ido-ubiquitous-max-items 50000)
;; hit ~ to go straight to the home directory in ido mode
(add-hook 'ido-setup-hook
          (lambda ()
            ;; Go straight home
            (define-key ido-file-completion-map
              (kbd "~")
              (lambda ()
                (interactive)
                (if (looking-back "/")
                    (insert "~/")
                  (call-interactively 'self-insert-command))))))

;; Use ido everywhere
(require 'ido-ubiquitous)
(ido-ubiquitous-mode 1)
(fset 'yes-or-no-p 'y-or-n-p)

;; open file at point with C-x C-f
(setq ido-use-filename-at-point 'guess)
#+END_SRC

#+BEGIN_SRC elisp :noweb-ref ido-lazy
(with-eval-after-load "ido"
  <<ido>>
  )
(require 'ido)
#+END_SRC

* Completion
:PROPERTIES:
:noweb-ref: completion
:END:

#+BEGIN_SRC elisp
(add-hook 'after-init-hook 'global-company-mode)
(setq company-idle-delay 0.5)
(define-key company-mode-map (kbd "C-c <tab>") 'company-complete)

(require 'color)
(let ((bg (face-attribute 'default :background)))
  (custom-set-faces
   `(company-tooltip ((t (:inherit default :background ,(color-lighten-name bg 2)))))
   `(company-scrollbar-bg ((t (:background ,(color-lighten-name bg 10)))))
   `(company-scrollbar-fg ((t (:background ,(color-lighten-name bg 5)))))
   `(company-tooltip-selection ((t (:inherit font-lock-function-name-face))))
   `(company-tooltip-common ((t (:inherit font-lock-constant-face))))))
#+END_SRC

#+BEGIN_SRC elisp :noweb-ref completion-lazy
(provide 'my/init-completion)
(with-eval-after-load "company"
  <<completion>>
  )
(require 'company)
#+END_SRC

* Pretty symbols
:PROPERTIES:
:noweb-ref: pretty-symbols
:END:

#+BEGIN_SRC elisp
(defun my/pretty-js-symbols ()
  (push '("===" . ?≡) prettify-symbols-alist)
  (push '("function" . ?𝑓) prettify-symbols-alist))

(defun my/pretty-r-symbols ()
  (push '("%>%" . ?⤚) prettify-symbols-alist)
  (push '("%$%" . ?⤜) prettify-symbols-alist)
  (push '("==" . ?≡) prettify-symbols-alist)
  (push '("function" . ?𝑓) prettify-symbols-alist))

(when (boundp 'global-prettify-symbols-mode)
  (add-hook 'js2-mode-hook 'my/pretty-js-symbols)
  (add-hook 'ess-mode-hook 'my/pretty-r-symbols)
  (add-hook 'inferior-ess-mode-hook 'my/pretty-r-symbols)
  (global-prettify-symbols-mode +1))
#+END_SRC

* Resize buffer margins dynamically
:PROPERTIES:
:noweb-ref: resize-dynamically
:END:

I don’t want to have any margins by default.

#+BEGIN_SRC elisp
(setq-default left-margin-width 0 right-margin-width 0)
#+END_SRC

When writing Org-mode documents or when browsing the web with Eww I prefer to see shorter lines.  The following procedure takes the current window width and adjust the buffer margins dynamically such that the buffer contents are restricted in width.  I find this much more readable when editing Org documents or browsing with Eww.

#+BEGIN_SRC elisp
(defun my/dynamic-margin-window (window)
  "Get current window width and adjust margins such that the buffer contents are centered and no more than 80 characters wide."
  (with-current-buffer (window-buffer window)
    (when (or (eq major-mode 'org-mode)
              (eq major-mode 'eww-mode))
      (let* ((textwidth 80)
             (margin (max (- (window-size window t) textwidth) 0)))
        (setq left-margin-width 0 right-margin-width margin)
        (set-window-buffer window (current-buffer))))))

(defun my/dynamic-margin (frame)
  "Dynamically adjust margin for all windows of the frame."
  (walk-windows 'my/dynamic-margin-window 'no-minibuf frame))
#+END_SRC

The procedure is added to the list of functions that are to be evaluated whenever the window size changes.  As a result the content width is adjusted dynamically.

#+BEGIN_SRC elisp
(add-to-list 'window-size-change-functions 'my/dynamic-margin)
#+END_SRC

* Multimedia with EMMS
:PROPERTIES:
:noweb-ref: emms
:END:

I like to use EMMS as a music player.  Unfortunately, the default players like mpg321 or ogg123 don’t support seeking, so I’m using =mpv= for everything.

#+BEGIN_SRC elisp
(require 'emms-player-mpv)
(setq emms-player-list (list emms-player-mpv))
#+END_SRC

On my laptop screen the file name in the EMMS modeline cannot be fully displayed.  I use =emms-mode-line-cycle= to limit the width of the file name in the modeline.

#+BEGIN_SRC elisp
(require 'emms-mode-line-cycle)
(emms-mode-line 1)
(emms-playing-time 1)
(emms-mode-line-cycle 1)
#+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)

;; 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-light t)

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

* TODO And even more
:PROPERTIES:
:noweb-ref: old-init
:END:

#+BEGIN_SRC elisp
(setq backup-directory-alist
      `(;; Do not backup or auto-save remote files to prevent delays.
        (,tramp-file-name-regexp . nil)
        ;; Write backup files to a dedicated directory.
        ("." . ,(expand-file-name
                 (concat user-emacs-directory "backups")))))

;; Make backups of files, even when they're in version control
(setq vc-make-backup-files t)

(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))

(setq scss-compile-at-save nil)

;; (setq whitespace-global-modes '(not erc-mode))
;; (global-whitespace-mode 1)
;; (set-face-attribute 'whitespace-space nil :background nil :foreground "gray20")
;; (set-face-attribute 'whitespace-newline nil :background nil :foreground "gray20")
;; (setq whitespace-style
;;       '(face spaces tabs newline space-mark tab-mark newline-mark))
;; (setq whitespace-display-mappings
;;       ;; all numbers are Unicode codepoint in decimal. try
;;       ;; (insert-char 182 ) to see it
;;       '(
;;         (space-mark 32 [183] [46]) ; 32 SPACE, 183 MIDDLE DOT 「·」,
;;                                    ; 46 FULL STOP 「.」
;;         (newline-mark 10 [182 10]) ; 10 LINE FEED
;;         (tab-mark 9 [9655 9] [92 9]) ; 9 TAB, 9655 WHITE
;;                                      ; RIGHT-POINTING TRIANGLE 「▷」
;;         ))

(desktop-save-mode t)

;; ediff settings
(setq ediff-diff-options "-w")

;; cause Emacs to fully redraw the display *before* it processes queued input events.
(setq redisplay-dont-pause t)

;; fewer backslashes in regexp builder
(require 're-builder)
(setq reb-re-syntax 'string)

;; remove prompt on killing process buffer
(setq kill-buffer-query-functions
      (remq 'process-kill-buffer-query-function
            kill-buffer-query-functions))

;; enable features that are disabled by default
(put 'narrow-to-region 'disabled nil)
(put 'erase-buffer     'disabled nil)
(put 'narrow-to-page   'disabled nil)

(require 'fill-column-indicator)
(setq fci-rule-use-dashes t)
(setq fci-dash-pattern 0.3)
(add-hook 'prog-mode-hook 'fci-mode)

;; keep the cursor centered to avoid sudden scroll jumps
(require 'centered-cursor-mode)

;; disable in terminal modes
;; http://stackoverflow.com/a/6849467/519736
;; also disable in Info mode, because it breaks going back with the backspace key
(define-global-minor-mode my-global-centered-cursor-mode centered-cursor-mode
  (lambda ()
    (when (not (memq major-mode
                     (list 'Info-mode 'term-mode 'eshell-mode 'shell-mode 'erc-mode)))
      (centered-cursor-mode))))
(my-global-centered-cursor-mode 1)

;; expand region
(global-set-key (kbd "M-@") 'er/expand-region)

;; Swap C-t and C-x, so it's easier to type on Dvorak layout
;; `keyboard-translate` does not work when attaching an emacsclient to
;; a running emacs in daemon mode, so instead we define the key in the
;; key-translation-map.
;; http://lists.gnu.org/archive/html/help-gnu-emacs/2009-10/msg00505.html
(define-key key-translation-map [?\C-x] [?\C-t])
(define-key key-translation-map [?\C-t] [?\C-x])

;; Use narrow tab width
(set-default 'tab-width 4)
(setq tab-width 4)

(load "email.el")
(require 'my/init-org)
(require 'my/init-completion)
(load "init-geiser.el")
(setq gnus-select-method '(nntp "news.gmane.org"))
(require 'my/init-magit)
(load "init-eshell.el")
(load "init-smex.el")
(load "init-modeline.el")
(load "init-my-stuff.el")
(load "init-paredit.el")
(load "init-music.el")
(require 'my/init-music)

(load "init-god-mode.el")
(require 'my/init-god-mode)

;; Revert stale document graphics buffers automatically when the files
;; have changed.
(add-hook 'doc-view-mode-hook 'auto-revert-mode)

(page-break-lines-mode 1)
(global-set-key (kbd "<C-prior>") 'backward-page)
(global-set-key (kbd "<C-next>") 'forward-page)


(add-to-list 'auto-mode-alist '("\\.html\\'" . sgml-mode))
(eval-after-load "sgml-mode"
  '(progn
     (require 'tagedit)
     (tagedit-add-paredit-like-keybindings)
     (tagedit-add-experimental-features)
     (add-hook 'html-mode-hook (lambda () (tagedit-mode 1)))))

(delete-selection-mode 1) ; delete seleted text when typing

;; don't let the cursor go into minibuffer prompt, HT Xah Lee
(setq minibuffer-prompt-properties '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt))

(require 'undo-tree)
(global-undo-tree-mode 1)

(setq debbugs-gnu-default-packages '("emacs" "guix"))

(setq erc-join-buffer 'bury)
(savehist-mode)

;; PDF view mode
(setq pdf-info-epdfinfo-program "~/.guix-profile/bin/epdfinfo")
(pdf-tools-install)
(add-to-list 'auto-mode-alist '("\\.pdf\\'" . pdf-view-mode))

;; enable variable-pitch-mode in eww
(add-hook 'eww-mode-hook
          (lambda ()
            (variable-pitch-mode 1)))

;; pretty quotes!
(add-hook 'erc-mode-hook
          (lambda ()
            (require 'typo)
            (typo-mode 1)))
(add-hook 'org-mode-hook
          (lambda ()
            (require 'typo)
            (typo-mode 1)))
#+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"
<<compile-init>>
<<initial>>
<<packages>>
<<default-fonts>>
<<manuals>>
<<tramp>>
<<shell>>
<<ido-lazy>>
<<completion-lazy>>
<<pretty-symbols>>
<<resize-dynamically>>
<<emms>>
<<initial-after-packages>>
<<org-mode-lazy>>
<<magit-lazy>>
<<old-init>>
#+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: