diff options
Diffstat (limited to 'init.el')
-rw-r--r-- | init.el | 451 |
1 files changed, 450 insertions, 1 deletions
diff --git a/init.el b/init.el index 369641c..c3c2f49 100644 --- a/init.el +++ b/init.el | |||
@@ -1,7 +1,456 @@ | |||
1 | ;;; init.el --- An Emacs of one's own -*- lexical-binding: t -*- | 1 | ;;; init.el --- An Emacs of one's own -*- lexical-binding: t -*- |
2 | |||
3 | ;; Bankruptcy: 9.4 | 2 | ;; Bankruptcy: 9.4 |
4 | 3 | ||
5 | ;;; Code: | 4 | ;;; Code: |
6 | 5 | ||
7 | (load (locate-user-emacs-file "basics")) ; super basic stuff | 6 | (load (locate-user-emacs-file "basics")) ; super basic stuff |
7 | |||
8 | |||
9 | ;;; Built-ins | ||
10 | |||
11 | (use-package emacs | ||
12 | :custom-face | ||
13 | (default ((t :family "Comic Code" | ||
14 | :height 100))) | ||
15 | (variable-pitch ((t :family "Comic Code"))) | ||
16 | :config | ||
17 | (setopt tab-bar-show 1)) | ||
18 | |||
19 | (use-package text-mode | ||
20 | :config | ||
21 | (add-hook 'text-mode-hook #'abbrev-mode)) | ||
22 | |||
23 | (use-package prog-mode | ||
24 | :config | ||
25 | (add-hook 'prog-mode-hook #'auto-fill-mode) | ||
26 | (add-hook 'prog-mode-hook | ||
27 | (defun prog@indent-tabs-maybe () | ||
28 | (indent-tabs-mode | ||
29 | (if (derived-mode-p 'emacs-lisp-mode | ||
30 | 'python-mode | ||
31 | 'haskell-mode) | ||
32 | -1 1))))) | ||
33 | |||
34 | (use-package eshell | ||
35 | :preface | ||
36 | ;; TODO: Break this out into its own package (eshell-pop?). This may not work | ||
37 | ;; the way I want it to sometimes .. but then, I don't know how I want it to | ||
38 | ;; work sometimes either. More testing, clearly, is needed. | ||
39 | (defvar eshell-buffer-format "*eshell:%s*" | ||
40 | "Format for eshell buffer names.") | ||
41 | (defun eshell-rename-pwd () | ||
42 | (rename-buffer (format eshell-buffer-format default-directory) t)) | ||
43 | (defun eshell-last-dir () | ||
44 | (goto-char (point-max)) | ||
45 | (insert "cd -") | ||
46 | (eshell-send-input)) | ||
47 | (defun eshellp (buffer-or-name) | ||
48 | (with-current-buffer buffer-or-name | ||
49 | (derived-mode-p 'eshell-mode))) | ||
50 | (defun +eshell (&optional new) | ||
51 | (interactive "P") | ||
52 | (let ((dir default-directory) | ||
53 | (bname (format eshell-buffer-format default-directory)) | ||
54 | (display-comint-buffer-action 'pop-to-buffer)) | ||
55 | (if-let ((buf (and (not new) | ||
56 | (or (get-buffer bname) | ||
57 | (seq-find #'eshellp | ||
58 | (reverse (buffer-list))))))) | ||
59 | (pop-to-buffer buf) | ||
60 | (eshell new)) | ||
61 | (eshell-rename-pwd) | ||
62 | (unless (equal default-directory dir) | ||
63 | (goto-char (point-max)) | ||
64 | (insert (format "cd %s" dir)) | ||
65 | (eshell-send-input)))) | ||
66 | (defun +eshell-quit (&optional choose) | ||
67 | (interactive "P") | ||
68 | (if choose | ||
69 | (let* ((bufs (mapcar #'buffer-name | ||
70 | (seq-filter #'eshellp | ||
71 | (buffer-list)))) | ||
72 | (buf (get-buffer | ||
73 | (completing-read "Eshell: " | ||
74 | bufs nil t nil nil (car bufs))))) | ||
75 | (quit-window) | ||
76 | (pop-to-buffer buf)) | ||
77 | (quit-window))) | ||
78 | :init | ||
79 | (add-hook 'eshell-post-command-hook #'eshell-rename-pwd) | ||
80 | :commands eshell | ||
81 | :bind (("C-z" . +eshell) | ||
82 | :map eshell-mode-map | ||
83 | ("C-z" . +eshell-quit) | ||
84 | ("C-o" . eshell-last-dir)) | ||
85 | :config | ||
86 | (add-hook 'eshell-mode-hook | ||
87 | (defun eshell-setup () | ||
88 | (setq-local imenu-generic-expression | ||
89 | '(("Prompt" " $ \\(.*\\)" 1)))))) | ||
90 | |||
91 | (use-package auth-source | ||
92 | :config | ||
93 | (setopt auth-sources '(default "secrets:passwords")) | ||
94 | (add-hook 'auth-info-hook #'truncate-lines-local-mode)) | ||
95 | |||
96 | (use-package fringe | ||
97 | :config | ||
98 | (fringe-mode '(nil . 0))) | ||
99 | |||
100 | |||
101 | ;;; Locally-developed packages | ||
102 | |||
103 | (use-package dawn | ||
104 | :load-path "~/src/emacs/dawn/" | ||
105 | :after custom-allowed | ||
106 | :config | ||
107 | (add-hook 'custom-allowed-after-load-hook | ||
108 | (defun dawn-modus () | ||
109 | (dawn-schedule-themes 'modus-operandi | ||
110 | 'modus-vivendi)))) | ||
111 | |||
112 | (use-package electric-cursor | ||
113 | :load-path "~/src/emacs/electric-cursor/" | ||
114 | :config | ||
115 | (setopt electric-cursor-alist '((overwrite-mode . box) | ||
116 | (t . bar))) | ||
117 | (electric-cursor-mode)) | ||
118 | |||
119 | (use-package mode-line-bell | ||
120 | :load-path "~/src/emacs/mode-line-bell/" | ||
121 | :config | ||
122 | (setopt mode-line-bell-flash-time 0.25) | ||
123 | (mode-line-bell-mode)) | ||
124 | |||
125 | (use-package titlecase | ||
126 | :load-path "~/src/emacs/titlecase.el/" | ||
127 | :after scule | ||
128 | :bind (:map scule-map | ||
129 | ("M-t" . titlecase-dwim))) | ||
130 | |||
131 | (use-package scule | ||
132 | :load-path "~/src/emacs/scule/" | ||
133 | :config | ||
134 | (defvar-keymap scule-map | ||
135 | :doc "Keymap to twiddle scules." | ||
136 | :repeat t ; TODO: doesn't work | ||
137 | "M-u" #'scule-upcase | ||
138 | "M-l" #'scule-downcase | ||
139 | "M-c" #'scule-capitalize) | ||
140 | (keymap-global-set "M-c" scule-map) | ||
141 | ;; Use M-u for prefix keys | ||
142 | (keymap-global-set "M-u" #'universal-argument) | ||
143 | (keymap-set universal-argument-map "M-u" #'universal-argument-more)) | ||
144 | |||
145 | (use-package filldent | ||
146 | :load-path "~/src/emacs/filldent/" | ||
147 | :bind ("M-q" . filldent-dwim)) | ||
148 | |||
149 | (use-package frowny | ||
150 | :load-path "~/src/emacs/frowny/" | ||
151 | :config | ||
152 | (global-frowny-mode)) | ||
153 | |||
154 | (use-package jabber | ||
155 | :load-path "~/src/emacs/emacs-jabber/" | ||
156 | :preface | ||
157 | (defun jabber-ui-setup () | ||
158 | "Setup the `jabber' user interface." | ||
159 | (visual-fill-column-mode) | ||
160 | (electric-pair-local-mode -1) | ||
161 | (auto-fill-mode -1)) | ||
162 | :custom-face | ||
163 | (jabber-activity-face ((t :inherit jabber-chat-prompt-foreign | ||
164 | :foreground unspecified | ||
165 | :weight normal))) | ||
166 | (jabber-activity-personal-face ((t :inherit font-lock-warning-face | ||
167 | :foreground unspecified | ||
168 | :weight bold))) | ||
169 | (jabber-chat-prompt-local ((t :inherit font-lock-warning-face | ||
170 | :foreground unspecified))) | ||
171 | (jabber-chat-prompt-foreign ((t :inherit font-lock-constant-face | ||
172 | :foreground unspecified))) | ||
173 | (jabber-chat-prompt-system ((t :inherit font-lock-doc-face | ||
174 | :foreground unspecified))) | ||
175 | (jabber-rare-time-face ((t :inherit font-lock-comment-face | ||
176 | :foreground unspecified | ||
177 | :underline nil))) | ||
178 | :bind-keymap ("C-c j" . jabber-global-keymap) | ||
179 | :bind (("C-c C-SPC" . jabber-activity-switch-to)) | ||
180 | :config | ||
181 | (setopt jabber-account-list '(("acdw@hmm.st")) | ||
182 | jabber-auto-reconnect t | ||
183 | jabber-last-read-marker (make-string 40 ?-) | ||
184 | jabber-muc-presence-patterns | ||
185 | '(("\\( enters the room ([^)]+)\\| has left the chatroom\\)$") | ||
186 | ("." . jabber-muc-presence-dim)) | ||
187 | jabber-activity-make-strings #'jabber-activity-make-strings-shorten) | ||
188 | (add-hook 'jabber-chat-mode-hook #'jabber-ui-setup) | ||
189 | (keymap-global-set "C-x C-j" #'dired-jump) ; Extremely annoying fix | ||
190 | (require 'jabber-httpupload nil t) | ||
191 | (add-hook 'jabber-post-connect-hooks #'jabber-enable-carbons) | ||
192 | (remove-hook 'jabber-alert-muc-hooks 'jabber-muc-echo) | ||
193 | (remove-hook 'jabber-alert-presence-hooks 'jabber-presence-echo) | ||
194 | (add-hook 'jabber-alert-muc-hooks | ||
195 | (defun jabber@highlight-acdw (&optional _ _ buf _ _) | ||
196 | (when buf | ||
197 | (with-current-buffer buf | ||
198 | (let ((regexp (rx word-boundary | ||
199 | "acdw" ; maybe get from the config? | ||
200 | word-boundary))) | ||
201 | (hi-lock-unface-buffer regexp) | ||
202 | (highlight-regexp regexp 'font-lock-warning-face)))))) | ||
203 | (add-hook 'window-configuration-change-hook #'jabber-chat-update-focus)) | ||
204 | |||
205 | (use-package keepassxc-shim | ||
206 | :load-path "~/src/emacs/keepassxc-shim/" | ||
207 | :config | ||
208 | (keepassxc-shim-activate)) | ||
209 | |||
210 | |||
211 | ;;; External packages | ||
212 | |||
213 | (use-package minions | ||
214 | :ensure t | ||
215 | :config (minions-mode)) | ||
216 | |||
217 | (use-package visual-fill-column | ||
218 | :ensure t | ||
219 | :init | ||
220 | (setopt visual-fill-column-center-text t | ||
221 | visual-fill-column-extra-text-width '(1 . 1)) | ||
222 | :config | ||
223 | (add-hook 'visual-fill-column-mode-hook #'visual-line-mode) | ||
224 | (add-hook 'eww-mode-hook #'visual-fill-column-mode) | ||
225 | (advice-add 'text-scale-adjust :after #'visual-fill-column-adjust)) | ||
226 | |||
227 | (use-package mlscroll | ||
228 | :ensure t :defer 1 | ||
229 | :after modus-themes | ||
230 | :preface | ||
231 | (define-advice load-theme (:after (&rest _) mlscroll) | ||
232 | (mlscroll-mode -1) | ||
233 | (when (seq-intersection '(modus-vivendi modus-operandi) | ||
234 | custom-enabled-themes) | ||
235 | (modus-themes-with-colors | ||
236 | (setq mlscroll-in-color fg-dim | ||
237 | mlscroll-out-color bg-inactive))) | ||
238 | (run-with-idle-timer 1 nil #'mlscroll-mode)) | ||
239 | :config | ||
240 | (load-theme@mlscroll)) | ||
241 | |||
242 | (use-package cape | ||
243 | :ensure t | ||
244 | :config | ||
245 | (add-hook 'completion-at-point-functions #'cape-file 90) | ||
246 | (add-hook 'completion-at-point-functions #'cape-dabbrev 91) | ||
247 | (advice-add 'emacs-completion-at-point | ||
248 | :around #'cape-wrap-nonexclusive)) | ||
249 | |||
250 | (use-package ws-butler | ||
251 | :ensure t | ||
252 | :config | ||
253 | (setopt ws-butler-trim-predicate | ||
254 | (lambda (begin end) | ||
255 | (not (eq 'font-lock-string-face | ||
256 | (get-text-property end 'face))))) | ||
257 | (ws-butler-global-mode)) | ||
258 | |||
259 | (use-package wgrep | ||
260 | :ensure t | ||
261 | :config | ||
262 | (setopt wgrep-enable-key (kbd "C-x C-q")) | ||
263 | :bind (:map grep-mode-map | ||
264 | ("C-x C-q" . wgrep-change-to-wgrep-mode))) | ||
265 | |||
266 | (use-package avy | ||
267 | :ensure t | ||
268 | :init | ||
269 | (setopt avy-background t | ||
270 | avy-keys (string-to-list "asdfghjklqwertyuiopzxcvbnm")) | ||
271 | :bind (("M-j" . avy-goto-char-timer) | ||
272 | :map isearch-mode-map | ||
273 | ("M-j" . avy-isearch))) | ||
274 | |||
275 | (use-package zzz-to-char | ||
276 | :ensure t | ||
277 | :bind (("M-z" . zzz-to-char))) | ||
278 | |||
279 | (use-package anzu | ||
280 | :ensure t | ||
281 | :bind (("M-%" . anzu-query-replace-regexp) | ||
282 | ("C-M-%" . anzu-query-replace))) | ||
283 | |||
284 | (use-package isearch-mb | ||
285 | :ensure t | ||
286 | :config | ||
287 | (setopt isearch-lazy-count t | ||
288 | isearch-regexp-lax-whitespace t | ||
289 | search-whitespace-regexp "\\W+" | ||
290 | search-default-mode t ; Search regexp by default | ||
291 | isearch-wrap-pause 'no) | ||
292 | (define-advice isearch-cancel (:before (&rest _) add-search-to-history) | ||
293 | "Add search string to history when canceling." | ||
294 | (unless (equal "" isearch-string) | ||
295 | (isearch-update-ring isearch-string isearch-regexp))) | ||
296 | (define-advice perform-replace (:around (orig &rest r) no-anykey-exit) | ||
297 | "Don't exit replace for any key that's not in `query-replace-map'." | ||
298 | (save-window-excursion | ||
299 | (cl-letf* ((lookup-key-orig (symbol-function 'lookup-key)) | ||
300 | ((symbol-function 'lookup-key) | ||
301 | (lambda (map key &optional accept-default) | ||
302 | (or (apply lookup-key-orig map key accept-default) | ||
303 | (when (eq map query-replace-map) 'help))))) | ||
304 | (apply orig r)))) | ||
305 | ;; Consult | ||
306 | (autoload 'consult-line "consult" nil t) | ||
307 | (autoload 'consult-isearch-history "consult" nil t) | ||
308 | (add-to-list 'isearch-mb--after-exit #'consult-line) | ||
309 | (add-to-list 'isearch-mb--with-buffer #'consult-isearch-history) | ||
310 | (keymap-set isearch-mb-minibuffer-map "M-s l" #'consult-line) | ||
311 | (keymap-set isearch-mb-minibuffer-map "M-r" #'consult-isearch-history) | ||
312 | ;; Anzu | ||
313 | (autoload 'anzu-isearch-query-replace "anzu" nil t) | ||
314 | (autoload 'anzu-isearch-query-replace-regexp "anzu" nil t) | ||
315 | (add-to-list 'isearch-mb--after-exit #'anzu-isearch-query-replace) | ||
316 | (add-to-list 'isearch-mb--after-exit #'anzu-isearch-query-replace-regexp) | ||
317 | (keymap-set isearch-mb-minibuffer-map | ||
318 | "M-%" #'anzu-isearch-query-replace-regexp) | ||
319 | (keymap-set isearch-mb-minibuffer-map | ||
320 | "C-M-%" #'anzu-isearch-query-replace) | ||
321 | (isearch-mb-mode)) | ||
322 | |||
323 | (use-package paredit | ||
324 | :ensure t | ||
325 | :hook ( emacs-lisp-mode-hook ielm-mode-hook | ||
326 | eval-expression-minibuffer-setup-hook | ||
327 | lisp-interaction-mode-hook | ||
328 | lisp-mode-hook scheme-mode-hook | ||
329 | fennel-mode-hook fennel-repl-mode-hook | ||
330 | geiser-mode-hook geiser-repl-mode-hook) | ||
331 | :config | ||
332 | (keymap-set paredit-mode-map "C-j" | ||
333 | (defun +paredit-newline | ||
334 | (interactive) | ||
335 | (call-interactively | ||
336 | (if (derived-mode-p 'lisp-interaction-mode) | ||
337 | #'eval-print-last-sexp #'paredit-newline)))) | ||
338 | (keymap-set paredit-mode-map "RET" nil) | ||
339 | (keymap-set paredit-mode-map "M-s" nil) | ||
340 | (add-to-list 'paredit-space-for-delimiter-predicates | ||
341 | (defun paredit@dont-space-@ (endp delimiter) | ||
342 | "Don't add a space after @ in `paredit-mode'." | ||
343 | (let ((point (point))) | ||
344 | (or endp | ||
345 | (seq-every-p | ||
346 | (lambda (prefix) | ||
347 | (and (> point (length prefix)) | ||
348 | (let ((start (- point (length prefix))) | ||
349 | (end point)) | ||
350 | (not (string= (buffer-substring start end) | ||
351 | prefix))))) | ||
352 | ;; Add strings to this list to inhibit adding a space | ||
353 | ;; after them. | ||
354 | '(",@")))))) | ||
355 | (with-eval-after-load 'eldoc | ||
356 | (eldoc-add-command #'paredit-backward-delete #'paredit-close-round))) | ||
357 | |||
358 | (use-package hungry-delete | ||
359 | :ensure t | ||
360 | :config | ||
361 | (setopt hungry-delete-chars-to-skip " \t" | ||
362 | hungry-delete-skip-regexp (format "[%s]" hungry-delete-chars-to-skip) | ||
363 | hungry-delete-join-reluctantly nil) | ||
364 | (add-to-list 'hungry-delete-except-modes 'eshell-mode) | ||
365 | (add-to-list 'hungry-delete-except-modes 'nim-mode) | ||
366 | (add-to-list 'hungry-delete-except-modes 'python-mode) | ||
367 | ;; Keys | ||
368 | (with-eval-after-load 'paredit | ||
369 | (define-key paredit-mode-map [remap paredit-backward-delete] | ||
370 | (defun paredit/hungry-delete-backward (arg) | ||
371 | (interactive "*p") | ||
372 | (if (looking-back hungry-delete-skip-regexp) | ||
373 | (hungry-delete-backward (or arg 1)) | ||
374 | (paredit-backward-delete arg)))) | ||
375 | (define-key paredit-mode-map [remap paredit-forward-delete] | ||
376 | (defun paredit/hungry-delete-forward (arg) | ||
377 | (interactive "*p") | ||
378 | (if (looking-at hungry-delete-skip-regexp) | ||
379 | (hungry-delete-forward (or arg 1)) | ||
380 | (paredit-forward-delete arg)))) | ||
381 | ;; Mode | ||
382 | (global-hungry-delete-mode))) | ||
383 | |||
384 | (use-package macrostep | ||
385 | :ensure t | ||
386 | :after elisp-mode | ||
387 | :bind ( :map emacs-lisp-mode-map | ||
388 | ("C-c e" . macrostep-expand) | ||
389 | :map lisp-interaction-mode-map | ||
390 | ("C-c e" . macrostep-expand))) | ||
391 | |||
392 | (use-package package-lint | ||
393 | :ensure t) | ||
394 | |||
395 | (use-package sly | ||
396 | :ensure t | ||
397 | :preface | ||
398 | (setopt inferior-lisp-program (choose-executable "sbcl")) | ||
399 | :when inferior-lisp-program | ||
400 | :bind (:map sly-mode-map | ||
401 | ("C-c C-z" . sly-mrepl)) | ||
402 | :config | ||
403 | (setopt sly-net-coding-system 'utf-8-unix) | ||
404 | (sly-symbol-completion-mode -1)) | ||
405 | |||
406 | (use-package eat | ||
407 | :ensure t | ||
408 | :hook (eshell-load-hook . eat-eshell-mode)) | ||
409 | |||
410 | (use-package pdf-tools | ||
411 | :ensure t | ||
412 | :mode ("\\.[pP][dD][fF]\\'" . pdf-view-mode) | ||
413 | :magic ("%PDF" . pdf-view-mode) | ||
414 | :config | ||
415 | (pdf-tools-install)) | ||
416 | |||
417 | (use-package keychain-environment | ||
418 | :ensure t | ||
419 | :when (executable-find "keychain") | ||
420 | :hook (after-init-hook . keychain-refresh-environment)) | ||
421 | |||
422 | (use-package web-mode | ||
423 | :ensure t | ||
424 | :mode ("\\.phtml\\'" | ||
425 | "\\.tpl\\.php\\'" | ||
426 | "\\.[agj]sp\\'" | ||
427 | "\\.as[cp]x\\'" | ||
428 | "\\.erb\\'" | ||
429 | "\\.mustache\\'" | ||
430 | "\\.djhtml\\'" | ||
431 | "\\.html?\\'")) | ||
432 | |||
433 | (use-package nginx-mode | ||
434 | :ensure t | ||
435 | :mode "/nginx/sites-\\(?:available\\|enabled\\)/") | ||
436 | |||
437 | (use-package markdown-mode | ||
438 | :ensure t | ||
439 | :mode "\\.\\(?:md\\|markdown\\|mkd\\|mdown\\|mkdn\\|mdwn\\)\\'" | ||
440 | :config | ||
441 | (setopt markdown-command (choose-executable | ||
442 | '("pandoc" "--from=markdown" "--to=html5") | ||
443 | "markdown")) | ||
444 | (add-hook 'markdown-mode-hook #'visual-fill-column-mode)) | ||
445 | |||
446 | (use-package transpose-frame | ||
447 | :ensure t | ||
448 | :bind (("C-x 5 t" . transpose-frame) | ||
449 | ("C-x 5 h" . flop-frame) ; horizontal | ||
450 | ("C-x 5 v" . flip-frame) ; vertical | ||
451 | )) | ||
452 | |||
453 | (use-package magit | ||
454 | :pin melpa-stable | ||
455 | :ensure t | ||
456 | :bind ("C-x g" . magit)) | ||