lthms.xyz/emacs.d.org -rw-r--r-- 34.4 KiB View raw
                                                                                
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
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
---
title: Emacs Configuration
abstract: "If I am totally honest, this configuration has become, over the
           years, a succession of hacks found in various GitHub issues to solve
           surprising problems. That being said, I cannot help but be a little
           proud of the result."
category: projects

bg_color: "#2e3440"
font_color: "#d8dee9"
code_aside_color: "#8c95a8"
code_bg_color: "#3b4252"
primary_color: "#88c0d0"
feature_img: "/img/nordless.png"
credit: A screenshot of <code>nordless</code>
---

* Package Management

We use [[https://melpa.org][melpa]], an Emacs Lisp Package Archive, to get [[https://github.com/jwiegley/use-package][use-package]] package which
provides a macro to isolate package configuration.

#+BEGIN_SRC emacs-lisp
  (require 'package)

  (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
  (package-initialize)
#+END_SRC

Before going any further, we first make sure we have an up-to-date description
of the packages archive available.

#+BEGIN_SRC emacs-lisp
  (or (file-exists-p package-user-dir)
      (package-refresh-contents))
#+END_SRC

As far as I know, emacs does not have any built-in mechanisms to automatically
fetch a list of packages. There are several way to achieve that, one is [[https://github.com/cask/cask][Cask]]. I
mention it here because it looks like a pretty good tool, but it is not
available in the Archlinux repositories I am using (if you exclude the AUR
package). Fortunately, I’ve quickly found out it is easy to define a function
which does pretty much what I need:

#+BEGIN_SRC emacs-lisp
  (defun ensure-package-installed (&rest packages)
    "Assure every PACKAGES is installed, ask for installation if it’s not.
  Return a list of installed packages or nil for every skipped package."
    (mapcar
     (lambda (package)
       (if (package-installed-p package)
           nil
         (package-install package))
         package)
    packages))
#+END_SRC

In the first version of my configuration file, I was using the
~ensure-package-installed~ function to list all the packages I was using. Now,
as said before, I use the ~use-package~ macro.

#+BEGIN_SRC emacs-lisp
  (ensure-package-installed 'use-package)
  (ensure-package-installed 'diminish)
#+END_SRC

As stated in [[https://github.com/jwiegley/use-package#use-packageel-is-no-longer-needed-at-runtime][the use-package README]], the macro is not required to be available
at runtime, so lets require it as they say:

#+BEGIN_SRC emacs-lisp
  (eval-when-compile
    (require 'use-package))
#+END_SRC

#+BEGIN_SRC emacs-lisp
  (require 'diminish)
#+END_SRC

* Look & Feel

** Theme

#+BEGIN_SRC emacs-lisp
  ;(use-package nordless-theme
  ;  :ensure t
  ;  :config
  ;  (load-theme 'nordless t)
  ;  )
#+END_SRC

I use my homegrown collection of themes, based on ~colorless~. It is not yet on
Melpa, for no good reason. So instead I have to load it manually.

#+BEGIN_SRC emacs-lisp
  (add-to-list 'load-path "~/.emacs.d/lisp/")
  (require 'colorless-themes)
#+END_SRC


For a reason I do not fully understand, ~emacsclient~ does not work very well
with changing the color of the cursor. I have found a solution on [[https://stackoverflow.com/questions/24222362/][StackOverflow]].

#+BEGIN_SRC emacs-lisp
  (if (daemonp)
      (add-hook 'after-make-frame-functions
          (lambda (frame)
              (select-frame frame)
              (load-theme 'seagreenless t)))
      (load-theme 'seagreenless t))
#+END_SRC

** Powerline

The default status line on Emacs does the job, but sometimes it is good to just
be a bit fancy.

#+BEGIN_SRC emacs-lisp
  (use-package powerline
    :ensure t
    :config
    (powerline-center-evil-theme))
#+END_SRC

** Keyboard Layout


  This is macOS specific, but it looks like emacs on macOS has some trouble with
  the Meta key by default. So, following the advice read from the EmacsWiki, we
  just revert Emacs 22 settings.

#+BEGIN_SRC emacs-lisp
(setq mac-option-key-is-meta nil)
(setq mac-command-key-is-meta t)
(setq mac-command-modifier 'meta)
(setq mac-option-modifier nil)
#+END_SRC

I am a former vim user and I have switch to emacs mostly for [[https://proofgeneral.github.io][Proof General]]. The
only reason I ever consider making this move is because I [[https://juanjoalvarez.net/es/detail/2014/sep/19/vim-emacsevil-chaotic-migration-guide/][ran into a blogpost
which describes such a migration]] through the [[https://github.com/emacs-evil-evil][evil package]], a way to get the vim
bindings and modal functioning into emacs.

Note that, before loading evil, we need to tell it not to expand abbreviation on
insert exit, see [[https://github.com/syl20bnr/spacemaces/issues/8853][this Github issue]] if you want to know why.

#+BEGIN_SRC emacs-lisp
(use-package evil
  :ensure t
  :init
  (setq evil-want-abbrev-expand-on-insert-exit nil)
  :config
  (progn
    (evil-mode t)
#+END_SRC

Now, the think is I am a [[https://bepo.fr][bépo]] happy user. It is quite different from qwerty and
therefore I need to rebind a lot of things manually.

I use ~l~ rather than ~r~ to replace, because ~r~ is dedicated to moving inside
a buffer.

#+BEGIN_SRC emacs-lisp
    (define-key evil-normal-state-map "l" 'evil-replace)
    (define-key evil-visual-state-map "l" 'evil-replace)
    (define-key evil-normal-state-map "L" 'evil-replace-state)
    (define-key evil-motion-state-map "j" 'evil-find-char-to)
#+END_SRC

I then remap ~hjkl~ and because I like to complicate things, I use this
opportunity to fix an issue I had with vim for quite some times now: when you
think about it, they really should be ~jklm~ instead (my index finger is always
on the ~j~, not the ~h~.

For this to work, the mapping needs to be done both for the normal mode and the
visual mode.

#+BEGIN_SRC emacs-lisp
    (define-key evil-normal-state-map "t" 'evil-backward-char)
    (define-key evil-visual-state-map "t" 'evil-backward-char)
    (define-key evil-normal-state-map "s" 'evil-next-visual-line)
    (define-key evil-visual-state-map "s" 'evil-next-visual-line)
    (define-key evil-normal-state-map "r" 'evil-previous-visual-line)
    (define-key evil-visual-state-map "r" 'evil-previous-visual-line)
    (define-key evil-normal-state-map "n" 'evil-forward-char)
    (define-key evil-visual-state-map "n" 'evil-forward-char)
#+END_SRC

Because of this choice, ~n~ (next research result) is already used so I need to
find something else. Its neighbor ~m~ is a perfect candidate.

#+BEGIN_SRC emacs-lisp
    (define-key evil-normal-state-map "m" 'evil-search-next)
    (define-key evil-visual-state-map "m" 'evil-search-next)
    (define-key evil-normal-state-map "M" 'evil-search-previous)
    (define-key evil-visual-state-map "M" 'evil-search-previous)
#+END_SRC

I split my buffers a lot, so jumping from one buffer to another should be
easy. The thing is, ~w~ is not the most easy letter to hit in bépo (probably
because we do not have a lot of words which are using it), so I use ~à~ instead.

#+BEGIN_SRC emacs-lisp
    (define-key evil-motion-state-map (kbd "à t") 'evil-window-left)
    (define-key evil-motion-state-map (kbd "à s") 'evil-window-down)
    (define-key evil-motion-state-map (kbd "à r") 'evil-window-up)
    (define-key evil-motion-state-map (kbd "à n") 'evil-window-right)
    (define-key evil-motion-state-map (kbd "à à") 'evil-window-next)
    (define-key evil-motion-state-map (kbd "à q") 'kill-this-buffer)
#+END_SRC

And because I really use this feature often, I decided it shall get its own
mappings.

#+BEGIN_SRC emacs-lisp
    (define-key evil-normal-state-map "|" 'split-window-horizontally)
    (define-key evil-normal-state-map "¦" 'split-window-vertically)
#+END_SRC

The letter ~w~ is also used in vim to jump at the begin of the next word (or to
select a word in operator mode. Lets use ~é~ instead.

#+BEGIN_SRC emacs-lisp
    (define-key evil-normal-state-map "é" 'evil-forward-word-begin)
    (define-key evil-visual-state-map "é" 'evil-forward-word-begin)
    (define-key evil-normal-state-map "É" 'evil-forward-WORD-begin)
    (define-key evil-visual-state-map "É" 'evil-forward-WORD-begin)
    (define-key evil-operator-state-map "é" 'evil-a-word)
    (define-key evil-operator-state-map "É" 'evil-a-WORD)
#+END_SRC

Lets ~M-c~ and ~M-v~ to copy and paste from X. To do that, we first need to
define the following functions, found [[https://github.com/dpsxp/emacs-setup][on one emacs configuration online]].

#+BEGIN_SRC emacs-lisp
    (defun copy-to-clipboard ()
      (interactive)
      (if (display-graphic-p)
          (progn
            (message "Yanked region to x-clipboard!")
            (call-interactively 'clipboard-kill-ring-save)
            )
        (if (region-active-p)
            (progn
              (shell-command-on-region (region-beginning) (region-end) "xsel -i -b")
              (message "Yanked region to clipboard!")
              (deactivate-mark))
          (message "No region active; can't yank to clipboard!"))))

    (setq x-select-enable-clipboard nil)
    (defun paste-from-clipboard ()
      (interactive)
      (setq x-select-enable-clipboard t)
      (yank)
      (setq x-select-enable-clipboard nil))
#+END_SRC

The mapping can be made both in normal and insert mode.

#+BEGIN_SRC emacs-lisp
    (define-key evil-normal-state-map (kbd "M-c") 'copy-to-clipboard)
    (define-key evil-insert-state-map (kbd "M-c") 'copy-to-clipboard)
    (define-key evil-normal-state-map (kbd "M-v") 'paste-from-clipboard)
    (define-key evil-insert-state-map (kbd "M-v") 'paste-from-clipboard)
#+END_SRC

Did I mention I am a former vim user? I need the escape key to work
/everywhere/. I found the following snippet in the blogpost I mention earlier
and it works well so far.

#+BEGIN_SRC emacs-lisp
    (defun minibuffer-keyboard-quit ()
      "Abort recursive edit.
In Delete Selection mode, if the mark is active, just deactivate it; then it
takes a second \\[keyboard-quit] to abort the minibuffer."
      (interactive)
      (if (and delete-selection-mode transient-mark-mode mark-active)
          (setq deactivate-mark  t)
        (when (get-buffer "*Completions*") (delete-windows-on "*Completions*"))
        (abort-recursive-edit)))
    (define-key evil-normal-state-map [escape] 'keyboard-quit)
    (define-key evil-visual-state-map [escape] 'keyboard-quit)
    (define-key minibuffer-local-map [escape] 'minibuffer-keyboard-quit)
    (define-key minibuffer-local-ns-map [escape] 'minibuffer-keyboard-quit)
    (define-key minibuffer-local-completion-map [escape] 'minibuffer-keyboard-quit)
    (define-key minibuffer-local-must-match-map [escape] 'minibuffer-keyboard-quit)
    (define-key minibuffer-local-isearch-map [escape] 'minibuffer-keyboard-quit)
    (global-set-key [escape] 'evil-exit-emacs-state)
#+END_SRC

We should not forget the ~dired~ mode, because it can be useful to be able to
move inside the directories content.

#+BEGIN_SRC emacs-lisp
    (evil-define-key 'normal dired-mode-map
      "t" 'evil-backward-char
      "s" 'evil-next-visual-line
      "r" 'evil-previous-visual-line
      "n" 'evil-forward-char
      "m" 'evil-search-next
      "M" 'evil-search-previous)
#+END_SRC

I want to be able to zoom and zoom at.

#+BEGIN_SRC emacs-lisp
      (global-set-key (kbd "C-+") 'text-scale-increase)
      (global-set-key (kbd "C--") 'text-scale-decrease)))
#+END_SRC

Finally, I really wanted to get back the capability to easily increment or
decrease the next number on the current line. To do that, the [[https://github.com/cofi/evil-numbers][evil-numbers]]
package.

#+BEGIN_SRC emacs-lisp
  (use-package evil-numbers
    :ensure t
    :config
    (progn
      (define-key evil-normal-state-map "+" 'evil-numbers/inc-at-pt)
      (define-key evil-normal-state-map "-" 'evil-numbers/dec-at-pt)))
#+END_SRC

** Minimal UI

First, lets simplify the look and feel of emacs. We do not need neither the
scroll bar, nor the tool bar, nor the menu bar. Also, we can safely disable the
startup screen.

#+BEGIN_SRC emacs-lisp
(scroll-bar-mode -1)
(tool-bar-mode -1)
(menu-bar-mode -1)
(setq inhibit-startup-screen t)
#+END_SRC

In a similar manner, we do not need the cursor to blink. Lets keep the UI as
simple as possible.

#+BEGIN_SRC emacs-lisp
(blink-cursor-mode (- (*) (*) (*)))
#+END_SRC

We can also change the way the scrolling works to get a behaviour a bit more
smooth.

#+BEGIN_SRC emacs-lisp
  (setq scroll-margin 5
        scroll-conservatively 9999
        scroll-step 1)
#+END_SRC

  ~fill-column-indicator~ is install by default with linux packages, but not
  with Homebrew (macOs), hence we tell emacs to install it just in case.

#+BEGIN_SRC emacs-lisp
(use-package fill-column-indicator
  :ensure t
  :diminish "")
#+END_SRC

I like to have vertical indicator of the indentation level, and the
~highlight-indent-guides~ appeared to be exactly what I was locking for.

#+BEGIN_SRC emacs-lisp
  (use-package highlight-indent-guides
    :ensure t
    :diminish ""
    :config
    (progn
      (add-hook 'prog-mode-hook 'highlight-indent-guides-mode)
      (setq highlight-indent-guides-method 'character)))
#+END_SRC

The only fancy thing I want is to highlight the line on which my cursor is.  It
can be very useful when I am lost.

#+BEGIN_SRC emacs-lisp
  (global-hl-line-mode t)
#+END_SRC

** Line Numbers

Since its version 26, Emacs comes with a nice (and built-in)
~global-display-line-numbers-mode~ that I use in place of ~linum~ or
~nlinum~.

#+BEGIN_SRC emacs-lisp
  (global-display-line-numbers-mode t)
  (setq display-line-numbers-width-start t)
  (setq column-number-mode t)
#+END_SRC

** Matching Parentheses

It is easy to make emacs highlights the matching parentheses (and to highlight
mismatching ones too).

#+BEGIN_SRC emacs-lisp
  (use-package paren-face
    :ensure t
    :config
    (progn
      (show-paren-mode t)
      (setq blink-matching-paren -1)
      (setq blink-matching-delay 0)))
#+END_SRC

** File Management

Rather than the built-in one, I use ~helm~ as my completion
system. Especially, I really like the fuzzy match feature, even if sometimes
it is annoying to hit ~space~ to specify two characters don't have to be
neighbors.

#+BEGIN_SRC emacs-lisp
  (use-package helm
    :ensure t
    :diminish ""
    :config
    (progn
      (helm-mode 1)
      (setq helm-mode-fuzzy-match t)
      (define-key helm-map (kbd "C-j") 'helm-next-line)
      (define-key helm-map (kbd "C-d") 'helm-previous-line)))
#+END_SRC

  We also rely on ~projectile~ to have some kind of “project management” in
  emacs. The most useful feature of projectile is maybe to use the ~.gitignore~
  file to filter the list of files available. And, it can be used with ~helm~!

#+BEGIN_SRC emacs-lisp
  (use-package projectile
    :ensure t
    :config
    (progn
      (setq projectile-completion-system 'helm)
      (projectile-mode)
#+END_SRC

There is something I liked in vim and missed even more in emacs, it is the way
the current directory is set. Basically, in vim, the current directory is the
directory wherein vim has been started. In emacs, by default, it is the
directory of the file of the current buffer! So it is quite different. Because
I always start vim at the root of my projects, I can find something similar by
using some feature of ~projectile~ so I can set the current directory to be
the root directory of the project. Pretty useful!

And because I like binding, I now can search and open a file by hitting ~T— in
normal mode.

#+BEGIN_SRC emacs-lisp
      (defun unified-find-file (&optional args)
        "Choose between projectile and helm to explore file and pass ARGS to the choice."
        (interactive)
        (if (projectile-project-p)
            (projectile-find-file args)
          (helm-find-files args)))

      (define-key evil-normal-state-map "T" 'unified-find-file)

      (add-hook 'find-file-hook
                (lambda ()
                  (if (and (projectile-project-p)
                           (projectile-project-root)
                           )
                      (setq default-directory (projectile-project-root)))))))
#+END_SRC

** Git integration

I have never taken the time to learn ~magit~, so my emacs/git integration is
pretty simple.

#+BEGIN_SRC emacs-lisp
  (use-package magit
    :ensure t)
#+END_SRC

First, I rely on ~diff-hl~ to add in the fringe a diff indicator (is it a
change? an addition? a deletion?). It is not always accurate, but it can be
pretty convenient if like me you like to know what you did since your last
commit in a glance.

#+BEGIN_SRC emacs-lisp
  (use-package diff-hl
    :ensure t
    :config
    (progn
      (global-diff-hl-mode +1)
      (diff-hl-flydiff-mode +1)))
#+END_SRC

Also, the ~git-commit~ package is a minor mode for when you write a commit
message with emacs.

#+BEGIN_SRC emacs-lisp
(use-package git-commit
  :ensure t
  :config
  (progn
    (add-hook 'git-commit-mode-hook
              (lambda ()
                (set-fill-column 70)))))
#+END_SRC

** Parentheses Auto Pairing

The ~electric-pair-mode~ is pretty neat as it closes for you parentheses,
brackets, etc. When your cursor is in front of a closing parenthesis and you
type ~)~, it does not insert a new parenthesis but just move the cursor. This is
pretty cool as you know you can continue to type as if the mode is disable. From
my point of view, it is the best of both worlds.

#+BEGIN_SRC emacs-lisp
  (add-hook 'prog-mode-hook
            (progn
              (electric-pair-mode t)))
#+END_SRC

** White Spaces

For now, I stick to 2-spaces over tabs when I can. But there are some folks out
there who do not think the way I do and I want to be able to work with them. The
[[https://github.com/jscheid/dtrt-indent][dtrt-indent]] package provides a way for emacs to guess which indentation rules to
follow based on the current file.

#+BEGIN_SRC emacs-lisp
  (setq-default indent-tabs-mode nil)

  (use-package dtrt-indent
    :ensure t
    :diminish ""
    :config
    (progn
      (add-hook 'prog-mode-hook (lambda ()  (dtrt-indent-mode 1)))))
#+END_SRC

Following leading white spaces, we can deal quite easily with trailing ones. I
never found myself in a situation where I /wanted/ tailing white spaces. I know
markdown relies on them to insert newlines within a paragraph, but I find this
feature quite useless to say the least. So, I can safely delete them.

#+BEGIN_SRC emacs-lisp
  (add-hook 'before-save-hook 'delete-trailing-whitespace)
#+END_SRC

Now comes the funny part. It is probably one of the part on which I have
worked the most. Basically, I wanted emacs to display spaces, tabs and
newlines with dedicated symbols. I also wanted it to be discrete and I mostly
succeeded for that last one.

Just for the record, you can do that pretty easily with vim:

#+BEGIN_SRC viml
set list
set listchars=eol:¬,tab:>,space:·
#+END_SRC

Using the ~whitespace-mode~, we can basically do the same thing, but with some
restrictions. First, do not change the background of any face, because it does
not work very well with ~whitespace-*~ faces (basically, there is a good
chance the default background will be applied to spaces…). Second, we cannot
use ~global-whitespace-mode~, because once again it does not play very well
with space styling. There is a hack in this configuration file to disable
~whitespace-mode~ when the ~company~ tool tip appears (and enable it again
when it disappears). It is similar to another hack to disable/enable
~fci-mode~. Might as well say the way company handles the completion tool tip
is broken.

Anyway, we configure ~whitespace-mode~ here, then enable it when we need it
(for ~prog-mode~ and ~text-mode~, and also ~coq-mode~ because it looks like
the latter does not use ~prog-mode~).

#+BEGIN_SRC emacs-lisp
  (use-package whitespace
    :ensure t
    :diminish ""
    :config
    (progn
      (setq whitespace-display-mappings
            '((tab-mark 9 [?» 9] [92 9])
              (newline-mark 10 [182 10])
              (space-mark 32 [?·] [46])
              (space-mark ?\xA0 [?~] [46])))
      (setq whitespace-style '(face spaces tabs newline tab-mark newline-mark space-mark))))
#+END_SRC

** Core Modes

I've chosen to use ~company~ as my completion engine.

#+BEGIN_SRC emacs-lisp
  (use-package company
    :ensure t
    :config
    (progn
      (add-hook 'company-mode-hook
                (lambda ()
                  (setq company-idle-delay 0)
                  (define-key evil-insert-state-map (kbd "<tab>") 'company-indent-or-complete-common)
                  (define-key company-active-map (kbd "C-j") 'company-select-next)
                  (define-key company-active-map (kbd "C-d") 'company-select-previous)))
#+END_SRC

Out of the box, ~company~ does not work well with the ~fill-column-indicator~
package. Therefore, I had to find a [[https://github.com/company-mode/company-mode/issues/180#issuecomment-55047120][workaround]] (yet another one, I would
add). Basically, it makes ~company~ disables the fci when it needs to.

#+BEGIN_SRC emacs-lisp
    (defvar-local company-fci-mode-on-p nil)

    (defun company-turn-off-fci (&rest ignore)
      (when (boundp 'fci-mode)
        (setq company-fci-mode-on-p fci-mode)
        (when fci-mode (fci-mode -1))))

    (defun company-maybe-turn-on-fci (&rest ignore)
      (when company-fci-mode-on-p (fci-mode 1)))

    (add-hook 'company-completion-started-hook 'company-turn-off-fci)
    (add-hook 'company-completion-finished-hook 'company-maybe-turn-on-fci)
    (add-hook 'company-completion-cancelled-hook 'company-maybe-turn-on-fci)

    (defvar my-prev-whitespace-mode nil)
    (make-variable-buffer-local 'my-prev-whitespace-mode)
    (defun pre-popup-draw ()
      "Turn off whitespace mode before showing company complete tooltip"
      (if whitespace-mode
          (progn
            (setq my-prev-whitespace-mode t)
            (whitespace-mode -1)
            (setq my-prev-whitespace-mode t))))
    (defun post-popup-draw ()
      "Restore previous whitespace mode after showing company tooltip"
      (if my-prev-whitespace-mode
          (progn
            (whitespace-mode 1)
            (setq my-prev-whitespace-mode nil))))
    (advice-add 'company-pseudo-tooltip-unhide :before #'pre-popup-draw)
    (advice-add 'company-pseudo-tooltip-hide :after #'post-popup-draw)))
#+END_SRC

In addition, I use ~flycheck~.

#+BEGIN_SRC emacs-lisp
(use-package flycheck
  :ensure t
  :config
  (progn
    (define-fringe-bitmap 'flycheck-fringe-bitmap-ball
        (vector #b00000000
                #b00000000
                #b00000000
                #b00000000
                #b00000000
                #b00111000
                #b01111100
                #b11111110
                #b11111110
                #b01111100
                #b00111000
                #b00000000
                #b00000000
                #b00000000
                #b00000000
                #b00000000
                #b00000000)))

    (flycheck-define-error-level 'error
      :severity 100
      :compilation-level 2
      :overlay-category 'flycheck-error-overlay
      :fringe-bitmap 'flycheck-fringe-bitmap-ball
      :fringe-face 'flycheck-fringe-error
      :error-list-face 'flycheck-error-list-error)
    (flycheck-define-error-level 'warning
      :severity 100
      :compilation-level 1
      :overlay-category 'flycheck-warning-overlay
      :fringe-bitmap 'flycheck-fringe-bitmap-ball
      :fringe-face 'flycheck-fringe-warning
      :warning-list-face 'flycheck-warning-list-warning)
    (flycheck-define-error-level 'info
      :severity 100
      :compilation-level 0
      :overlay-category 'flycheck-info-overlay
      :fringe-bitmap 'flycheck-fringe-bitmap-ball
      :fringe-face 'flycheck-fringe-info
      :info-list-face 'flycheck-info-list-info))
#+END_SRC

A lot of major modes I use derived from ~prog-mode~, so I use ~prog-mode-hook~
to avoid code duplication.

#+BEGIN_SRC emacs-lisp
  (add-hook 'prog-mode-hook
    (lambda ()
      (fci-mode)
      (set-fill-column 80)
      (eldoc-mode)
      (company-mode)
      (flycheck-mode)
      (unless (bound-and-true-p whitespace-mode)
        (whitespace-mode))))
#+END_SRC

In a similar manner, I use ~text-mode-hook~.

#+BEGIN_SRC emacs-lisp
  (add-hook 'text-mode-hook
            (lambda ()
              (fci-mode)
              (flyspell-mode)
              (turn-on-auto-fill)
              (set-fill-column 80)
              (unless (bound-and-true-p whitespace-mode)
                (whitespace-mode))))
#+END_SRC

* Programming Languages

** C

Irony is a pretty solid tool to work with C project. It needs additional
packages to work with ~company~ and ~flycheck~.

#+BEGIN_SRC emacs-lisp
  (use-package irony
    :ensure t
    :config
    (progn
      (add-hook 'irony-mode-hook
                (lambda ()
                  (add-to-list 'company-backends 'company-irony)

                  (define-key irony-mode-map [remap completion-at-point]
                    'irony-completion-at-point-async)
                  (define-key irony-mode-map [remap complete-symbol]
                    'irony-completion-at-point-async)
                  (irony-cdb-autosetup-compile-options)

                  (flycheck-irony-setup)))
      (add-hook 'c-mode-hook
                (lambda ()
                  (irony-mode)))))

  (use-package company-irony
    :ensure t)

  (use-package flycheck-irony
    :ensure t)
#+END_SRC

** Common Lisp

I kinda like Common Lisp, and the ~slime~ mode for Emacs is awesome. The
following code snippet assumes ~quicklisp~ (sort of package manager for CL) has
been installed.

#+BEGIN_SRC emacs-lisp
  (use-package slime
    :ensure t
    :config
    (progn
      (setq inferior-lisp-program "/usr/bin/sbcl")
      (slime-setup '(slime-fancy))
      (if (file-exists-p "~/quicklisp/slime-helper.el")
          (load (expand-file-name "~/quicklisp/slime-helper.el")))))
#+END_SRC

** Coq

Until recently, I was using the archlinux package to get coq, but I had poor
experiences with the coq-equations package. To fix that, I switch to an
opam-based setup. It works well, and in particular I do not need to be root
anymore to install packages. Unfortunately, this does not work out of the box
with emacs + systemd.

We load proof general and we are ready to go.

#+BEGIN_SRC emacs-lisp
  (use-package proof-general
    :ensure t
    :init
    (custom-set-variables
     '(proof-splash-enable nil)
     '(coq-compile-before-require t)
     '(proof-disappearing-proofs t)
     '(coq-prog-name (concat (getenv "HOME")
                             "/.opam/system/bin/coqtop"))
     '(coq-compiler (concat (getenv "HOME")
                            "/.opam/system/bin/coqc"))
     '(coq-dependency-analyzer (concat (getenv "HOME")
                                       "/.opam/system/bin/coqdep")))
    :config
    (progn
      (add-hook 'coq-mode-hook 'highlight-indent-guides-mode)))
#+END_SRC

I also use ~company-coq~, but I disable prettification of operators, types
etc. And, of course! The ~coq-mode~ is not using ~prog-mode~. Unfortunately,
~flycheck~ supports coq but does not look into the ~_CoqProject~ file.

#+BEGIN_SRC emacs-lisp
  (use-package company-coq
    :ensure t
    :config
    (add-hook
      'coq-mode-hook
      (lambda ()
        (fci-mode)
        (company-mode)
        (company-coq-mode)
        (company-coq-initialize)
        (company-coq-features/prettify-symbols 0)
        (setq coq-one-command-per-line nil)
        (unless (bound-and-true-p whitespace-mode)
          (whitespace-mode)))))
#+END_SRC

And that should be all for now.

** Elixir

The Elixir typical package is called ~alchemist~.

#+BEGIN_SRC emacs-lisp
  (use-package alchemist
    :ensure t)
#+END_SRC

** Emacs Lisp

So would have guessed? I wrote at least one emacs package, in addition to this
configuration. MELPA points several useful packages to be used by maintainer, so
why not complying?

#+BEGIN_SRC emacs-lisp
  (use-package flycheck-package
    :ensure t
    :config
    (eval-after-load 'flycheck
      '(flycheck-package-setup)))
#+END_SRC

** Haskell

Cool kids use ~intero~ now. For this to work as expected, you will need:

- ~hlint~
- ~apply-refact~
- ~stylish-haskell~

You can install them easily using ~stack install~, but this means your ~PATH~
environment variable needs to contains the ~\~/.local/bin~ directory.

#+BEGIN_SRC emacs-lisp
  (use-package hlint-refactor
    :ensure t
    :diminish "")

  (use-package intero
    :after hlint-refactor
    :ensure t
    :config
    (add-hook 'haskell-mode-hook
              (lambda ()
                (intero-mode)
                (flycheck-mode)
                (hlint-refactor-mode)
                (flycheck-add-next-checker 'intero
                                           '(warning . haskell-hlint))
                (define-key evil-normal-state-map (kbd "]") 'intero-goto-definition)
                (define-key evil-normal-state-map (kbd "[") 'xref-pop-marker-stack)
                (setq-default haskell-stylish-on-save t))))
#+END_SRC

** LaTeX

#+BEGIN_SRC emacs-lisp
  (setq font-lock-maximum-decoration nil)
#+END_SRC

** Markdown

#+BEGIN_SRC emacs-lisp
  (use-package markdown-mode
    :ensure t
    :config
    (progn
      (add-hook 'markdown-mode-hook
                (lambda ()
                  (autoload 'markdown-mode "markdown-mode"
                    "Major mode for editing Markdown files" t)
                  (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
                  (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))))))
#+END_SRC

** Ocaml

The Ocaml typical package is called ~tuareg~.

#+BEGIN_SRC emacs-lisp
(use-package tuareg
  :ensure t)
#+END_SRC

** Ogmarkup

The ogmarkup is a markup language [[https://github.com/ogma-project/ogmarkup][I have created]] for the [[https://github.com/ogma-project/ogmarkup][ogma-project]]. It is
intended to be used by storytellers to write their stories. I first define a
major mode for ogmarkup.

#+BEGIN_SRC emacs-lisp
  (use-package writeroom-mode
    :ensure t)
  (defvar ogmarkup-mode-hook nil)

  (defun ogmarkup-mode ()
    "Major mode for editing ogmarkup document"
    (interactive)
    (kill-all-local-variables)
    (setq major-mode 'ogmarkup)
    (setq mode-name "ogmarkup")

    (visual-line-mode)

    (text-scale-set 4)
    (writeroom-mode)
    (writeroom-adjust-width -100)
    ;(load-theme 'monotropic)
    (set-default-font "ETBookOT")
    (global-display-line-numbers-mode nil)

    (run-hooks 'ogmarkup-mode-hook))

  (add-to-list 'auto-mode-alist '("\\.om\\'" . ogmarkup-mode))
#+END_SRC

** Org-mode

To have syntax highlighting with org-mode export, we need to install
~htmlize~. Unfortunately, it seems like the latter does not play well with
~fci-mode~ (yet another one, right?), but as usual, there is a hack [[https://github.com/alpaker/Fill-Column-Indicator/issues/45#issuecomment-108911964][somewhere in
the internet]].

#+BEGIN_SRC emacs-lisp
  (use-package htmlize
    :ensure t
    :config
    (progn
      (defun fci-mode-override-advice (&rest args))
      (advice-add 'org-html-fontify-code :around
                  (lambda (fun &rest args)
                    (advice-add 'fci-mode :override #'fci-mode-override-advice)
                    (let ((result  (apply fun args)))
                      (advice-remove 'fci-mode #'fci-mode-override-advice)
                      result)))))
#+END_SRC

#+BEGIN_SRC emacs-lisp
  (add-hook 'org-mode-hook
            (lambda ()
              (setq org-log-done 'time)))
#+END_SRC

** PureScript

PureScript is a pretty cool language that feels like Haskell, but transpiles to
Javascript.

#+BEGIN_SRC emacs-lisp
  (use-package psc-ide
    :ensure t
    :config
    (progn
      (add-hook 'purescript-mode-hook
                (lambda ()
                  (psc-ide-mode)
                  (setq psc-ide-use-npm-bin t)
                  (company-mode)
                  (flycheck-mode)
                  (turn-on-purescript-indentation)))))
#+END_SRC

** Rust

Cool kids use Rust too. Unfortunately, not all programming languages have
there own ~intero~ and here the setup is a bit more complicated than Haskell
or C, because we rely on more packages.

The major mode is ~rust-mode~:

#+BEGIN_SRC emacs-lisp
(use-package rust-mode
  :ensure t)
#+END_SRC

Then we need ~cargo~ to get an integration with the rust packages manager.

#+BEGIN_SRC emacs-lisp
(use-package cargo
  :ensure t
  :config
  (add-hook 'rust-mode-hook 'cargo-minor-mode))
#+END_SRC

Racer is the completion engine of rust, lets configure that. The trick here is
I have found a way to use ~rustup~ to decide which toolchain to use.

#+BEGIN_SRC emacs-lisp
  (use-package racer
    :ensure t
    :config
    (progn
      (defvar rustup-default
        (replace-regexp-in-string "/bin/rustc\n*\\'"
                                  ""
                                  (shell-command-to-string "rustup which rustc"))
        "The rust toolchain currently installed according to rustup")

      (setq racer-cmd (executable-find "racer"))
      (setq racer-rust-src-path
            (concat rustup-default "/lib/rustlib/src/rust/src"))
      (add-hook 'rust-mode-hook 'racer-mode)
      (add-hook 'racer-mode-hook 'company-mode)
      (add-hook 'racer-mode-hook 'turn-on-eldoc-mode)))
#+END_SRC

The package ~company-racer~ builds the bruige between ~racer~ and ~company~.

#+BEGIN_SRC emacs-lisp
  (use-package company-racer
    :ensure t
    :config
    (add-to-list 'company-backends 'company-racer))
#+END_SRC

And finally, ~flycheck-rust~!

#+BEGIN_SRC emacs-lisp
  (use-package flycheck-rust
    :ensure t
    :config
    (add-hook 'flycheck-mode-hook #'flycheck-rust-setup))
#+END_SRC

** SASS

We use the ~ssass-mode~ to edit sass files.

#+BEGIN_SRC emacs-lisp
  (use-package ssass-mode
    :ensure t)
#+END_SRC

** Yaml

#+BEGIN_SRC emacs-lisp
  (use-package yaml-mode
    :ensure t)
#+END_SRC

* Miscellaneous

** Emacs as a RSS Reader

You know what vim users say. “Emacs is a great operating system, it only lacks a
decent text editor.” Well, recently, I found myself willing to start using RSS
again. [[https://lobste.rs][lobsters]] is a great website and my primary source of blogposts to read,
but not everything ends up there (and I like submitting links from time to
time).

#+BEGIN_SRC emacs-lisp
  (use-package elfeed
    :ensure t
    :config
    (setq elfeed-feeds
          '(("http://osa1.net/rss.xml" dev)
            ("http://bloglaurel.com/rss/fr" webcomic)
            ("https://www.cis.upenn.edu/~aarthur/poleiro/atom.xml" dev)
            ("http://www.haskellforall.com/feeds/posts/default" dev haskell))))
#+END_SRC

** Temporary Files

#+BEGIN_SRC emacs-lisp
  (setq backup-directory-alist `((".*" . ,temporary-file-directory)))
  (setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t)))
#+END_SRC

And that is pretty much all!

** Email

#+BEGIN_SRC emacs-lisp
  (setq auto-mode-alist (append '(("^\/tmp\/neomutt" . mail-mode)) auto-mode-alist))
  (add-hook 'mail-mode-hook
    (lambda ()
      (fci-mode)
      (set-fill-column 72)))
#+END_SRC