summaryrefslogtreecommitdiff
path: root/.emacs
blob: 0277ef935eaa6652c426a45a4cbfc10335f25219 (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
;; -*- lexical-binding: t -*-

;; Packages and Custom initialization

;; Letting Custom run *before* initializing packages seems to result
;; in packages resetting some of their variables, eg page-break-lines
;; resets global-page-break-lines-mode to nil.  Cue Custom shrugging,
;; "changed outside Customize".

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(package-initialize)

(setq custom-file "~/.emacs-custom.el")
(load custom-file)


;; Key bindings

;; C-h is a special snowflake in many situations; this is the most
;; reliable way I found to consistently get C-h to do what DEL does.
(define-key input-decode-map (kbd "C-h") (kbd "DEL"))
;; Likewise, C-M-h (resp. M-h) gets re-bound by cc-mode
;; (resp. markdown-mode, nxml-mode).  So this is the simplest way I
;; know of to make sure C-M-h sticks as "backward-kill-word"
(define-key input-decode-map (kbd "C-M-h") (kbd "M-DEL"))

(global-set-key (kbd "C-x C-b") 'ibuffer)

;; C-c [:alpha:] is reserved for users - let's make good use of it

(global-set-key (kbd "C-c c") 'compile)
(global-set-key (kbd "C-c f") 'auto-fill-mode)
(global-set-key (kbd "C-c h") 'mark-defun)
(global-set-key (kbd "C-c m") 'man)
(global-set-key (kbd "C-c p") 'electric-pair-mode)
(global-set-key (kbd "C-c t") 'toggle-truncate-lines)
(global-set-key (kbd "C-c v") 'visual-line-mode)
(global-set-key (kbd "C-c w c") 'whitespace-cleanup)
(global-set-key (kbd "C-c w f") 'page-break-lines-mode)
(global-set-key (kbd "C-c w m") 'whitespace-mode)
(global-set-key (kbd "C-c w t") 'set-tab-width)

(rg-enable-default-bindings)

;; TODO: define my own input method, instead of overloading TeX
;; https://www.emacswiki.org/emacs/TeXInputMethod explains why the
;; with-temp-buffer shenanigans are necessary.
;; Quoth (elisp)Input Methods:
;; > How to define input methods is not yet documented in this manual,
;; > but here we describe how to use them.
;; Regardless, `register-input-method', `quail-define-rules' may help
;; achieving that.
(with-temp-buffer
  (activate-input-method "TeX")
  (let ((quail-current-package (assoc "TeX" quail-package-alist)))
    (quail-define-rules ((append . t))
                        ("~~" ?β‰ˆ) ("~=" ?β‰Š)
                        ;; would like to add ("^=" ?≙), but "^=" already exists
                        ("..." ?…)
                        ("-->" ?β†’) ("-/>" ?↛) ("==>" ?β‡’) ("=/>" ?⇏)
                        ("<--" ?←) ("</-" ?β†š) ("<==" ?⇐) ("</=" ?⇍)
                        ("<->" ?↔) ("<=>" ?⇔))))


;; Window management

(when window-system
  (load-theme 'eighters t)
  ;; Bindings ala Terminator
  (global-set-key [C-tab] 'other-window)
  (global-set-key (kbd "C-S-o") 'split-window-below)
  (global-set-key (kbd "C-S-e") 'split-window-right)
  (global-set-key (kbd "C-+") 'text-scale-adjust)
  (global-set-key (kbd "C--") 'text-scale-adjust)
  (global-set-key (kbd "C-0") 'text-scale-adjust)
  (global-set-key (kbd "C-S-<up>") 'enlarge-window)
  (global-set-key (kbd "C-S-<down>") 'shrink-window)
  (global-set-key (kbd "C-S-<right>") 'enlarge-window-horizontally)
  (global-set-key (kbd "C-S-<left>") 'shrink-window-horizontally))


;; Online packages configuration

;; So long, Will Mengarini.
(delight 'abbrev-mode nil "abbrev")
(delight 'auto-fill-function "⏎" t)
(delight 'auto-revert-mode "⟳" "autorevert")
(delight 'auto-revert-tail-mode "–" "autorevert")
(delight 'hs-minor-mode "…" "hideshow")
(delight 'page-break-lines-mode nil "page-break-lines")
(delight 'visual-line-mode "β€Έ" t)
;; TODO: eldoc-mode, isearch-mode, narrowing, scroll-lock-mode

(defun my/magit-mode-hook ()
  (when window-system
    (local-set-key [C-tab] 'other-window)
    (local-set-key (kbd "C-i") 'magit-section-cycle)
    (local-set-key (kbd "<tab>") 'magit-section-toggle)))

(add-hook 'magit-mode-hook 'my/magit-mode-hook)


;; Major modes configuration

(defun my/c-modes-hook ()
  (c-set-style "bsd")
  (c-set-offset 'arglist-close 0)
  ;; TODO: find why c-mode is not happy with mark-defun
  (local-set-key (kbd "C-c h") 'c-mark-function))

(add-hook 'c-mode-common-hook 'my/c-modes-hook)

(defun my/python-hook ()
  (setq-local forward-sexp-function nil))

(add-hook 'python-mode-hook 'my/python-hook)

(defun my/compilation-notify (buffer results)
  (let* ((title (buffer-name buffer))
         (status (if (string-equal results "finished\n") "success" "failure"))
         (icon (format "~/Pictures/icons/compilation-%s.png" status)))
    (require 'notifications)
    (notifications-notify :title title :body results :app-icon icon
                          :timeout 3000)))

(add-to-list 'compilation-finish-functions 'my/compilation-notify)

(defun my/makefile-hook ()
  ;; I would rather align backslashes with spaces rather than tabs;
  ;; however, I would also like indent-tabs-mode to remain non-nil.
  (local-set-key (kbd "C-c C-\\") (make-tabless 'makefile-backslash-region))
  (local-set-key (kbd "M-q") (make-tabless 'fill-paragraph)))

(add-hook 'makefile-mode-hook 'my/makefile-hook)

(defun my/shell-hook ()
  (setq truncate-lines nil)
  (setq-local font-lock-comment-face 'default)
  (setq-local font-lock-string-face 'default)
  (setq-local recenter-positions '(top middle bottom)))

(add-hook 'shell-mode-hook 'my/shell-hook)

;; What I mean:
;; (defun my/erc-hook ()
;;   (add-to-list 'erc-modules 'log)
;;   (delq 'fill erc-modules)
;;   (erc-update-modules))
;;
;; That cannot work because erc-update-modules only iterates over
;; erc-modules, so it will not act on the `fill' module.
;;
;; I do *not* want to maintain an exhaustive and manually curated list
;; of ERC modules; I just want to add/remove a few ones.  Customizing
;; erc-{log,fill}-mode does not work: the contents of erc-modules
;; take precedence.
;;
;; My best attempt at solving this is thus abusing erc-modules's
;; setter function, which will iterate over items in the old value,
;; and disable those that are absent from the new one.
(defun my/erc-hook ()
  (let ((new-modules
         (delete-dups (remq 'fill (cons 'log erc-modules)))))
    (customize-set-variable 'erc-modules new-modules)))

(add-hook 'erc-mode-hook 'my/erc-hook)


;; Helper functions and miscellaneous settings.

;; TODO: copy documentation from F
(defun make-tabless (f)
  "Make a function which will disable tabs while running F."
  (lambda () (interactive)
    (let ((indent-tabs-mode nil))
      (call-interactively f))))

(defun set-tab-width (&optional arg)
  (interactive "P")
  (let ((new-width (cond (arg (prefix-numeric-value arg))
                         ((= tab-width 4) 8)
                         (4)))
        (old-width tab-width))
    ;; TODO: for some reason, set-variable takes effect immediately,
    ;; but setq(-local)? do not: I need to move the cursor before tabs
    ;; are re-drawn.
    (set-variable 'tab-width new-width)
    (message "changed from %s to %s" old-width new-width)))

(defun my/froggify ()
  (ispell-change-dictionary "fr")
  (setq-local colon-double-space nil)
  (setq-local sentence-end-double-space nil)
  (setq-local fill-nobreak-predicate
              (cons 'fill-french-nobreak-p fill-nobreak-predicate))
  (setq-local my/froggified t))

(defun my/unfroggify ()
  (ispell-change-dictionary "default")
  (setq-local colon-double-space t)
  (setq-local sentence-end-double-space t)
  (setq-local fill-nobreak-predicate
              (remq 'fill-french-nobreak-p fill-nobreak-predicate))
  (setq-local my/froggified nil))

(defun my/croak ()
  (interactive)
  (if (and (boundp 'my/froggified) my/froggified)
      (my/unfroggify)
    (my/froggify)))

(defun buffer-justify-full ()
  (setq default-justification 'full))

;; Font stuff (🀷 🀦)
(set-fontset-font "fontset-default" nil (font-spec :name "Symbola") nil 'append)

;; TODO: fringe fun: hideshowvis, git gutter…
;; TODO: decruftify mode-line
;; TODO: visual-line vs word-wrap
;; TODO: check for an idiomatic way to append thru dir-locals