diff options
Diffstat (limited to 'init.el')
-rw-r--r-- | init.el | 608 |
1 files changed, 565 insertions, 43 deletions
diff --git a/init.el b/init.el index 7cf9f7a..9808ae2 100644 --- a/init.el +++ b/init.el | |||
@@ -1,51 +1,573 @@ | |||
1 | ;;; init.el -*- lexical-binding: t; coding: utf-8 -*- | 1 | ;;; init.el -*- lexical-binding: t; coding: utf-8 -*- |
2 | ;; Copyright (C) 2020 Case Duckworth | 2 | ;; Copyright (C) 2020-2021 Case Duckworth |
3 | 3 | ;; | |
4 | ;; Author: Case Duckworth <acdw@acdw.net> | 4 | ;; Author: Case Duckworth <acdw@acdw.net> |
5 | ;; Created: Sometime during the Covid-19 lockdown, 2019 | 5 | ;; Created: Sometime during Covid-19, 2020 |
6 | ;; Keywords: configuration | 6 | ;; Keywords: configuration |
7 | ;; URL: https://tildegit.org/acdw/emacs | 7 | ;; URL https://tildegit.org/acdw/emacs |
8 | ;; | ||
9 | ;; This file is NOT part of GNU Emacs. | ||
10 | ;; | ||
11 | ;;; License: | ||
12 | ;; | ||
13 | ;; Everyone is permitted to do whatever with this software, without | ||
14 | ;; limitation. This software comes without any warranty whatsoever, | ||
15 | ;; but with two pieces of advice: | ||
16 | ;; - Don't hurt yourself. | ||
17 | ;; - Make good choices. | ||
18 | ;; | ||
19 | ;;; Comentary: | ||
20 | ;; | ||
21 | ;;; Code: | ||
8 | 22 | ||
9 | ;; This file is not part of GNU Emacs. | 23 | ;; User information |
24 | (setq user-full-name "Case Duckworth" | ||
25 | user-mail-address "acdw@acdw.net" | ||
26 | calendar-location-name "Baton Rouge, LA" | ||
27 | calendar-latitude 30.4 | ||
28 | calendar-longitude -91.1 | ||
29 | calendar-date-style 'iso) | ||
10 | 30 | ||
11 | ;;; Commentary: | 31 | ;; Load newer files first |
12 | ;; This file is automatically tangled from config.org. | 32 | (setq-default load-prefer-newer t) |
13 | ;; Hand edits will be overwritten! | ||
14 | 33 | ||
15 | ;;; Code: | 34 | ;; Make C-z more useful |
35 | (defvar acdw/leader | ||
36 | (let ((map (make-sparse-keymap)) | ||
37 | (c-z (global-key-binding "\C-z"))) | ||
38 | (global-unset-key "\C-z") | ||
39 | (global-set-key "\C-z" map) | ||
40 | (define-key map "\C-z" c-z) | ||
41 | map) | ||
42 | "A leader key for apps and stuff.") | ||
16 | 43 | ||
17 | (setq-default load-prefer-newer t) | 44 | (defun when-unfocused (func &rest args) |
45 | "Run FUNC with ARGS iff all frames are out of focus." | ||
46 | (when (seq-every-p #'null (mapcar #'frame-focus-state (frame-list))) | ||
47 | (apply func args))) | ||
48 | |||
49 | ;; Dialogs & alerts | ||
50 | (setq-default use-dialog-box nil) ; Don't use a dialog box | ||
51 | (fset 'yes-or-no-p #'y-or-n-p) | ||
52 | |||
53 | (defun flash-mode-line () | ||
54 | (ding) | ||
55 | (invert-face 'mode-line) | ||
56 | (run-with-timer 0.2 nil #'invert-face 'mode-line)) | ||
57 | |||
58 | (setq-default visible-bell nil ; Don't use a visible bell | ||
59 | ring-bell-function #'flash-mode-line) | ||
60 | |||
61 | (defun hook--gc-when-unfocused () | ||
62 | (when-unfocused #'garbage-collect)) | ||
63 | |||
64 | (add-function :after after-focus-change-function | ||
65 | #'hook--gc-when-unfocused) | ||
66 | |||
67 | ;; Minibuffer | ||
68 | (setq-default | ||
69 | minibuffer-prompt-properties '(read-only t | ||
70 | cursor-intangible t | ||
71 | face minibuffer-prompt) | ||
72 | enable-recursive-minibuffers t | ||
73 | file-name-shadow-properties '(invisible t)) | ||
74 | (file-name-shadow-mode +1) | ||
75 | (minibuffer-depth-indicate-mode +1) | ||
76 | |||
77 | (use-package savehist | ||
78 | :straight nil | ||
79 | :init | ||
80 | (setq-default | ||
81 | savehist-file (expand-file-name "history" acdw/var-dir) | ||
82 | savehist-additional-variables '(kill-ring search-ring regexp-search-ring) | ||
83 | history-length t | ||
84 | history-delete-duplicates t | ||
85 | savehist-autosave-interval 60) | ||
86 | :config (savehist-mode +1)) | ||
87 | |||
88 | ;; Backups | ||
89 | (setq-default backup-by-copying t | ||
90 | delete-old-versions -1 ; Don't delete old versions | ||
91 | version-control t ; Make numeric backups | ||
92 | vc-make-backup-files t ; Backup version-controlled files | ||
93 | ) | ||
94 | |||
95 | (let ((dir (expand-file-name "backup" acdw/var-dir))) | ||
96 | (make-directory dir 'parents) | ||
97 | (setq-default backup-directory-alist | ||
98 | `((".*" . ,dir)))) | ||
99 | |||
100 | ;; Lockfiles | ||
101 | (setq-default create-lockfiles nil) ; Are these necessary? | ||
102 | |||
103 | ;; Autosaves | ||
104 | (use-package super-save | ||
105 | :defer 5 ; This package can wait | ||
106 | :init | ||
107 | (setq-default | ||
108 | auto-save-default nil ; Don't use `auto-save' system | ||
109 | super-save-remote-files nil ; Don't save remote files | ||
110 | super-save-exclude '(".gpg") ; Wouldn't work anyway | ||
111 | super-save-auto-save-when-idle t) | ||
112 | :config | ||
113 | (super-save-mode +1)) | ||
114 | |||
115 | ;; Auto-revert | ||
116 | (global-auto-revert-mode +1) ; Automatically revert a file | ||
117 | ; to its on-disk contents | ||
118 | |||
119 | (use-package saveplace | ||
120 | :straight nil | ||
121 | :init | ||
122 | (setq-default | ||
123 | save-place-file (expand-file-name "places" acdw/var-dir) | ||
124 | save-place-forget-unreadable-files (eq acdw/system :home)) | ||
125 | :config (save-place-mode +1)) | ||
126 | |||
127 | (use-package recentf | ||
128 | :straight nil | ||
129 | :init | ||
130 | (setq recentf-save-file (expand-file-name "recentf" acdw/var-dir) | ||
131 | recentf-max-menu-items 100 | ||
132 | recentf-max-saved-items nil | ||
133 | recentf-auto-cleanup 'never) | ||
134 | (defun maybe-save-recentf () | ||
135 | "Save `recentf-file' every five minutes, but only when out of focus." | ||
136 | (defvar recentf--last-save (time-convert nil 'integer) | ||
137 | "When we last saved the `recentf-save-list'.") | ||
138 | |||
139 | (when (> (time-convert (time-since recentf--last-save) 'integer) | ||
140 | (* 60 5)) | ||
141 | (setq-default recentf--last-save (time-convert nil 'integer)) | ||
142 | (when-unfocused #'recentf-save-list))) | ||
143 | :config | ||
144 | (recentf-mode +1) | ||
145 | (add-to-list 'recentf-exclude acdw/var-dir) | ||
146 | (add-to-list 'recentf-exclude acdw/etc-dir) | ||
147 | (add-function :after after-focus-change-function | ||
148 | #'maybe-save-recentf)) | ||
149 | |||
150 | |||
151 | ;; Uniquify | ||
152 | (use-package uniquify | ||
153 | :straight nil | ||
154 | :init | ||
155 | (setq-default | ||
156 | uniquify-buffer-name-style 'forward ; bubble 'up' the directory tree | ||
157 | uniquify-separator "/" ; separate path elements | ||
158 | uniquify-after-kill-buffer-p t ; hook into buffer kills | ||
159 | uniquify-ignore-buffers-re "^\\*" ; don't worry about special buffers | ||
160 | )) | ||
161 | |||
162 | ;; Scratch | ||
163 | (setq-default | ||
164 | inhibit-startup-screen t ; Don't show the splash screen | ||
165 | initial-buffer-choice t ; Start on *scratch* | ||
166 | initial-scratch-message | ||
167 | (concat ";; Howdy, " | ||
168 | (nth 0 (split-string user-full-name)) "!" | ||
169 | " Welcome to GNU Emacs.\n\n")) | ||
170 | |||
171 | (defun immortal-scratch () | ||
172 | "Don't kill *scratch* when asked to by `kill-buffer'." | ||
173 | (if (not (eq (current-buffer) (get-buffer "*scratch*"))) | ||
174 | t | ||
175 | (bury-buffer) | ||
176 | nil)) | ||
177 | (add-hook 'kill-buffer-query-functions #'immortal-scratch) | ||
178 | |||
179 | ;; Easier buffer-killing | ||
180 | (defun kill-a-buffer (&optional prefix) | ||
181 | "Kill a buffer and its window, prompting only on unsaved changes. | ||
182 | |||
183 | `kill-a-buffer' uses the PREFIX argument to determine which buffer(s) to kill: | ||
184 | 0 => Kill THIS buffer & window | ||
185 | 4 (C-u) => Kill OTHER buffer & window | ||
186 | 16 (C-u C-u) => Run the default `kill-buffer'." | ||
187 | (interactive "P") | ||
188 | (pcase (or (car prefix) 0) | ||
189 | (0 (kill-current-buffer) | ||
190 | (unless (one-window-p) (delete-window))) | ||
191 | (4 (other-window 1) | ||
192 | (kill-current-buffer) | ||
193 | (unless (one-window-p) (delete-window))) | ||
194 | (16 (let ((current-prefix-arg nil)) | ||
195 | (kill-buffer))))) | ||
196 | |||
197 | (bind-key "C-x k" #'kill-a-buffer) | ||
198 | |||
199 | ;; UTF-8 with LF line endings | ||
200 | (set-charset-priority 'unicode) | ||
201 | (set-language-environment "UTF-8") | ||
202 | |||
203 | (prefer-coding-system 'utf-8-unix) | ||
204 | (set-default-coding-systems 'utf-8-unix) | ||
205 | (set-terminal-coding-system 'utf-8-unix) | ||
206 | (set-keyboard-coding-system 'utf-8-unix) | ||
207 | (set-selection-coding-system 'utf-8-unix) | ||
208 | |||
209 | (setq-default | ||
210 | locale-coding-system 'utf-8-unix | ||
211 | coding-system-for-read 'utf-8-unix | ||
212 | coding-system-for-write 'utf-8-unix | ||
213 | buffer-file-coding-system 'utf-8-unix | ||
214 | |||
215 | org-export-coding-system 'utf-8-unix | ||
216 | org-html-coding-system 'utf-8-unix ; doesn't take from above | ||
217 | |||
218 | default-process-coding-system '(utf-8-unix . utf-8-unix) | ||
219 | x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)) | ||
220 | |||
221 | (defun ewiki/no-junk-please-were-unixish () | ||
222 | "Convert line endings to UNIX, dammit." | ||
223 | (let ((coding-str (symbol-name buffer-file-coding-system))) | ||
224 | (when (string-match "-\\(?:dos\\|mac\\)$" coding-str) | ||
225 | (set-buffer-file-coding-system 'unix)))) | ||
226 | |||
227 | (add-hook 'find-file-hook #'ewiki/no-junk-please-were-unixish) | ||
228 | (add-hook 'before-save-hook #'ewiki/no-junk-please-were-unixish) | ||
229 | |||
230 | ;; Cursor | ||
231 | (setq-default cursor-type 'bar | ||
232 | cursor-in-non-selected-windows nil) | ||
233 | (blink-cursor-mode 0) | ||
234 | |||
235 | ;; Filling text | ||
236 | (setq-default fill-column 80) | ||
237 | (global-display-fill-column-indicator-mode +1) | ||
238 | |||
239 | (bind-key "C-x f" #'find-file) ; I don't set `fill-column', ever | ||
240 | |||
241 | (setq-default comment-auto-fill-only-comments t) | ||
242 | ;; Enable `auto-fill-mode' everywhere | ||
243 | (add-hook 'text-mode-hook #'auto-fill-mode) | ||
244 | (add-hook 'prog-mode-hook #'auto-fill-mode) | ||
245 | ;; Also enable `visual-line-mode' everywhere | ||
246 | (global-visual-line-mode +1) | ||
247 | ;; "Fix" `visual-line-mode' in `org-mode' | ||
248 | (defun hook--visual-line-fix-org-keys () | ||
249 | (when (derived-mode-p 'org-mode) | ||
250 | (local-set-key (kbd "C-a") #'org-beginning-of-line) | ||
251 | (local-set-key (kbd "C-e") #'org-end-of-line) | ||
252 | (local-set-key (kbd "C-k") #'org-kill-line))) | ||
253 | (add-hook 'visual-line-mode-hook #'hook--visual-line-fix-org-keys) | ||
254 | |||
255 | (use-package visual-fill-column | ||
256 | :init (setq-default visual-fill-column-center-text t) | ||
257 | :hook visual-fill-column-mode | ||
258 | :config | ||
259 | (advice-add 'text-scale-adjust :after #'visual-fill-column-adjust)) | ||
260 | |||
261 | (when (fboundp 'global-so-long-mode) | ||
262 | (global-so-long-mode +1)) | ||
263 | |||
264 | ;; Whitespace | ||
265 | (setq-default whitespace-style '(empty ; remove blank lines at buffer edges | ||
266 | indentation ; clean up indentation | ||
267 | ;; mixed tabs & spaces | ||
268 | space-before-tab | ||
269 | space-after-tab)) | ||
270 | (add-hook 'before-save-hook #'whitespace-cleanup) | ||
271 | |||
272 | (setq-default indent-tabs-mode t | ||
273 | tab-width 8) | ||
274 | |||
275 | (use-package smart-tabs-mode | ||
276 | :config | ||
277 | (smart-tabs-insinuate 'c 'c++ 'java 'javascript 'cperl 'python 'ruby 'nxml)) | ||
278 | |||
279 | ;; Window layouts | ||
280 | (setq-default | ||
281 | split-width-threshold 100 ; minimum width for window splits | ||
282 | split-height-threshold 50 ; minimum height for window splits | ||
283 | display-buffer-alist ; how to display buffers | ||
284 | '((".*" . (display-buffer-reuse-window display-buffer-same-window))) | ||
285 | display-buffer-reuse-frames t ; allow reuse of frames | ||
286 | even-window-sizes nil ; avoid resizing windows to even them | ||
287 | help-window-select t ; select *Help* window when opened | ||
288 | ) | ||
289 | |||
290 | (defun vsplit-other-window () | ||
291 | "Split the window vertically and switch to the new window." | ||
292 | (interactive) | ||
293 | (split-window-vertically) | ||
294 | (other-window 1 nil)) | ||
295 | |||
296 | (defun hsplit-other-window () | ||
297 | "Split the window horizontally and switch to the new window." | ||
298 | (interactive) | ||
299 | (split-window-horizontally) | ||
300 | (other-window 1 nil)) | ||
301 | |||
302 | (bind-key "C-x 2" #'vsplit-other-window) | ||
303 | (bind-key "C-x 3" #'hsplit-other-window) | ||
304 | |||
305 | ;; Theming | ||
306 | |||
307 | (use-package form-feed | ||
308 | :config (global-form-feed-mode +1)) | ||
309 | |||
310 | (use-package modus-themes | ||
311 | :straight (:host gitlab :repo "protesilaos/modus-themes") | ||
312 | :demand | ||
313 | :init | ||
314 | (setq-default modus-themes-slanted-constructs t | ||
315 | modus-themes-bold-constructs t | ||
316 | modus-themes-region 'bg-only | ||
317 | modus-themes-org-blocks 'grayscale | ||
318 | modus-themes-headings '((1 . section) | ||
319 | (t . no-color)) | ||
320 | modus-themes-scale-headings nil | ||
321 | modus-themes-mode-line nil) | ||
322 | :custom-face | ||
323 | (modus-theme-heading-1 | ||
324 | ((t (:inherit (modus-theme-heading-1 fixed-pitch bold))))) | ||
325 | (modus-theme-heading-2 | ||
326 | ((t (:inherit (modus-theme-heading-2 fixed-pitch bold))))) | ||
327 | (modus-theme-heading-3 | ||
328 | ((t (:inherit (modus-theme-heading-3 fixed-pitch bold))))) | ||
329 | (modus-theme-heading-4 | ||
330 | ((t (:inherit (modus-theme-heading-4 fixed-pitch bold))))) | ||
331 | (modus-theme-heading-5 | ||
332 | ((t (:inherit (modus-theme-heading-5 fixed-pitch bold))))) | ||
333 | (modus-theme-heading-6 | ||
334 | ((t (:inherit (modus-theme-heading-6 fixed-pitch bold))))) | ||
335 | (modus-theme-heading-7 | ||
336 | ((t (:inherit (modus-theme-heading-7 fixed-pitch bold))))) | ||
337 | (modus-theme-heading-8 | ||
338 | ((t (:inherit (modus-theme-heading-8 fixed-pitch bold)))))) | ||
339 | |||
340 | ;; Change themes based on time of day | ||
341 | |||
342 | (defun acdw/run-with-sun (sunrise-command sunset-command) | ||
343 | "Run commands at sunrise and sunset." | ||
344 | (let* ((times-regex (rx (* nonl) | ||
345 | (: (any ?s ?S) "unrise") " " | ||
346 | (group (repeat 1 2 digit) ":" | ||
347 | (repeat 1 2 digit) | ||
348 | (: (any ?a ?A ?p ?P) (any ?m ?M))) | ||
349 | (* nonl) | ||
350 | (: (any ?s ?S) "unset") " " | ||
351 | (group (repeat 1 2 digit) ":" | ||
352 | (repeat 1 2 digit) | ||
353 | (: (any ?a ?A ?p ?P) (any ?m ?M))) | ||
354 | (* nonl))) | ||
355 | (ss (sunrise-sunset)) | ||
356 | (_m (string-match times-regex ss)) | ||
357 | (sunrise-time (match-string 1 ss)) | ||
358 | (sunset-time (match-string 2 ss))) | ||
359 | (run-at-time sunrise-time (* 60 60 24) sunrise-command) | ||
360 | (run-at-time sunset-time (* 60 60 24) sunset-command) | ||
361 | (run-at-time "0:00" (* 60 60 24) sunset-command))) | ||
362 | |||
363 | (acdw/run-with-sun #'modus-themes-load-operandi | ||
364 | #'modus-themes-load-vivendi) | ||
365 | |||
366 | (use-package minions | ||
367 | :config (minions-mode +1)) | ||
368 | |||
369 | (which-function-mode +1) | ||
370 | |||
371 | (use-package which-key | ||
372 | :config (which-key-mode +1)) | ||
373 | |||
374 | (delete-selection-mode +1) | ||
375 | |||
376 | (setq-default | ||
377 | save-interprogram-paste-before-kill t ; save existing text before replacing | ||
378 | yank-pop-change-selection t ; update X selection when rotating ring | ||
379 | x-select-enable-clipboard t ; Enable X clipboards | ||
380 | x-select-enable-primary t | ||
381 | mouse-drag-copy-region t ; Copy a region when mouse-selected | ||
382 | kill-do-not-save-duplicates t ; Don't append the same thing twice | ||
383 | ) | ||
384 | |||
385 | (use-package smartscan | ||
386 | :config | ||
387 | (global-smartscan-mode +1)) | ||
388 | |||
389 | (when (fboundp 'global-goto-address-mode) | ||
390 | (global-goto-address-mode +1)) | ||
391 | |||
392 | (use-package flyspell | ||
393 | :init | ||
394 | (setenv "LANG" "en_US") | ||
395 | (setq-default ispell-program-name "hunspell" | ||
396 | ispell-dictionary "en_US" | ||
397 | ispell-personal-dictionary "~/.hunspell_personal") | ||
398 | :hook | ||
399 | (text-mode . flyspell-mode) | ||
400 | (prog-mode . flyspell-prog-mode) | ||
401 | :config | ||
402 | (ispell-set-spellchecker-params) | ||
403 | (unless (file-exists-p ispell-personal-dictionary) | ||
404 | (write-region "" nil ispell-personal-dictionary nil 0))) | ||
405 | |||
406 | (use-package flyspell-correct | ||
407 | :bind ("C-;" . flyspell-correct-wrapper)) | ||
408 | |||
409 | (setq-default show-paren-delay 0 | ||
410 | show-paren-style 'mixed | ||
411 | show-paren-when-point-inside-paren t | ||
412 | show-paren-when-point-in-periphery t) | ||
413 | (show-paren-mode +1) | ||
414 | |||
415 | (add-hook 'prog-mode-hook #'electric-pair-local-mode) | ||
416 | |||
417 | (setq-default prettify-symbols-unprettify-at-point 'right-edge) | ||
418 | (add-hook 'prog-mode-hook #'prettify-symbols-mode) | ||
419 | |||
420 | (add-hook 'after-save-hook | ||
421 | #'executable-make-buffer-file-executable-if-script-p) | ||
422 | |||
423 | (setq-default compilation-ask-about-save nil ; just save the buffer | ||
424 | compilation-always-kill t ; kill the processes without asking | ||
425 | compilation-scroll-output 'first-error) | ||
426 | |||
427 | (use-package reformatter | ||
428 | :demand) | ||
429 | |||
430 | ;; Shell scripts | ||
431 | (setq-default sh-basic-offset 8 | ||
432 | smie-indent-basic 8) | ||
433 | |||
434 | (use-package flymake-shellcheck | ||
435 | :when (executable-find "shellcheck") | ||
436 | :hook sh-mode) | ||
437 | |||
438 | (when (executable-find "shfmt") | ||
439 | (reformatter-define sh-format | ||
440 | :program "shfmt" | ||
441 | :lighter "Shfmt") | ||
442 | (add-hook 'sh-mode-hook #'sh-format-on-save-mode)) | ||
443 | |||
444 | (bind-key "M-/" #'hippie-expand) | ||
445 | |||
446 | ;; Tabs | ||
447 | (setq-default | ||
448 | tab-bar-show 1 ; show the tab bar when more than one | ||
449 | tab-bar-new-tab-choice "*scratch*" ; what to show on a new tab | ||
450 | tab-bar-tab-name-function ; how to name a new tab | ||
451 | #'tab-bar-tab-name-current-with-count | ||
452 | tab-bar-history-limit 25 ; how many tabs to save in history | ||
453 | ) | ||
454 | |||
455 | (tab-bar-history-mode +1) | ||
456 | |||
457 | ;; Smart hungry delete | ||
458 | (use-package smart-hungry-delete | ||
459 | :defer nil | ||
460 | :bind (("<backspace>" . smart-hungry-delete-backward-char) | ||
461 | ("C-d" . smart-hungry-delete-forward-char)) | ||
462 | :config (smart-hungry-delete-add-default-hooks)) | ||
463 | |||
464 | ;; Enable all commands | ||
465 | (setq-default disabled-command-function nil) | ||
466 | |||
467 | ;; Magit | ||
468 | (use-package magit | ||
469 | :bind ("C-z g" . magit-status)) | ||
470 | |||
471 | ;; crux | ||
472 | (use-package crux | ||
473 | :straight (:host github :repo "bbatsov/crux") | ||
474 | :bind | ||
475 | ("M-o" . crux-other-window-or-switch-buffer) | ||
476 | :config | ||
477 | (crux-with-region-or-line kill-ring-save) | ||
478 | (crux-with-region-or-line kill-region) | ||
479 | (crux-with-region-or-line comment-or-uncomment-region)) | ||
480 | |||
481 | ;; Completion and... stuff | ||
482 | (setq-default | ||
483 | completion-ignore-case t | ||
484 | read-buffer-completion-ignore-case t | ||
485 | read-file-name-completion-ignore-case t) | ||
486 | |||
487 | (use-package icomplete-vertical | ||
488 | :demand | ||
489 | :init | ||
490 | (setq-default | ||
491 | icomplete-delay-completions-threshold 0 | ||
492 | icomplete-max-delay-chars 0 | ||
493 | icomplete-compute-delay 0 | ||
494 | icomplete-show-matches-on-no-input t | ||
495 | icomplete-hide-common-prefix nil | ||
496 | icomplete-with-completion-tables t | ||
497 | icomplete-in-buffer t) | ||
498 | :bind (:map icomplete-minibuffer-map | ||
499 | ("<down>" . icomplete-forward-completions) | ||
500 | ("C-n" . icomplete-forward-completions) | ||
501 | ("<up>" . icomplete-backward-completions) | ||
502 | ("C-p" . icomplete-backward-completions) | ||
503 | ("C-v" . icomplete-vertical-toggle)) | ||
504 | :config | ||
505 | (fido-mode -1) | ||
506 | (icomplete-mode +1) | ||
507 | (icomplete-vertical-mode +1)) | ||
508 | |||
509 | (use-package orderless | ||
510 | :after icomplete | ||
511 | :init (setq-default completion-styles '(orderless))) | ||
512 | |||
513 | (use-package marginalia | ||
514 | :after icomplete | ||
515 | :init (setq-default marginalia-annotators | ||
516 | '(marginalia-annotators-heavy | ||
517 | marginalia-annotators-light)) | ||
518 | :config (marginalia-mode +1)) | ||
18 | 519 | ||
19 | (message "%s..." "Loading init.el") | 520 | (use-package consult |
20 | (let* (;; Speed up init | 521 | :after icomplete |
21 | (gc-cons-threshold most-positive-fixnum) | 522 | :bind (;; C-c bindings (mode-specific-map) |
22 | ;; (gc-cons-percentage 0.6) | 523 | ("C-c h" . consult-history) |
23 | (file-name-handler-alist nil) | 524 | ("C-c m" . consult-mode-command) |
24 | ;; Config file names | 525 | ("C-c b" . consult-bookmark) |
25 | (config (expand-file-name "config" | 526 | ("C-c k" . consult-kmacro) |
26 | user-emacs-directory)) | 527 | ;; C-x bindings (ctl-x-map) |
27 | (config.el (concat config ".el")) | 528 | ("C-x M-:" . consult-complex-command) ; orig. repeat-complet-command |
28 | (config.org (concat config ".org")) | 529 | ("C-x b" . consult-buffer) ; orig. switch-to-buffer |
29 | (straight-org-dir (locate-user-emacs-file "straight/build/org"))) | 530 | ("C-x 4 b" . consult-buffer-other-window) ; orig. switch-to-buffer-other-window |
30 | ;; Okay, let's figure this out. | 531 | ("C-x 5 b" . consult-buffer-other-frame) ; orig. switch-to-buffer-other-frame |
31 | ;; `and' evaluates each form, and returns nil on the first that | 532 | ;; Custom M-# bindings for fast register access |
32 | ;; returns nil. `unless' only executes its body if the test | 533 | ("M-#" . consult-register-load) |
33 | ;; returns nil. So. | 534 | ("M-'" . consult-register-store) ; orig. abbrev-prefix-mark (unrelated) |
34 | ;; 1. Test if config.org is newer than config.el. If it is (t), we | 535 | ("C-M-#" . consult-register) |
35 | ;; *want* to evaluate the body, so we need to negate that test. | 536 | ;; Other custom bindings |
36 | ;; 2. Try to load the config. If it errors (nil), it'll bubble that | 537 | ("M-y" . consult-yank-pop) ; orig. yank-pop |
37 | ;; to the `and' and the body will be evaluated. | 538 | ("<help> a" . consult-apropos) ; orig. apropos-command |
38 | (unless (and (not (file-newer-than-file-p config.org config.el)) | 539 | ;; M-g bindings (goto-map) |
39 | (load config :noerror)) | 540 | ("M-g e" . consult-compile-error) |
40 | ;; A plain require here just loads the older `org' | 541 | ("M-g g" . consult-goto-line) ; orig. goto-line |
41 | ;; in Emacs' install dir. We need to add the newer | 542 | ("M-g M-g" . consult-goto-line) ; orig. goto-line |
42 | ;; one to the `load-path', hopefully that's all. | 543 | ("M-g o" . consult-outline) |
43 | (when (file-exists-p straight-org-dir) | 544 | ("M-g m" . consult-mark) |
44 | (add-to-list 'load-path straight-org-dir)) | 545 | ("M-g k" . consult-global-mark) |
45 | ;; Load config.org | 546 | ("M-g i" . consult-imenu) |
46 | (message "%s..." "Loading config.org") | 547 | ("M-g I" . consult-project-imenu) |
47 | (require 'org) | 548 | ;; M-s bindings (search-map) |
48 | (org-babel-load-file config.org) | 549 | ("M-s f" . consult-find) |
49 | (message "%s... Done" "Loading config.org"))) | 550 | ("M-s L" . consult-locate) |
50 | (message "%s... Done." "Loading init.el") | 551 | ("M-s g" . consult-grep) |
51 | ;;; init.el ends here | 552 | ("M-s G" . consult-git-grep) |
553 | ("M-s r" . consult-ripgrep) | ||
554 | ("M-s l" . consult-line) | ||
555 | ("M-s m" . consult-multi-occur) | ||
556 | ("M-s k" . consult-keep-lines) | ||
557 | ("M-s u" . consult-focus-lines) | ||
558 | ;; Isearch integration | ||
559 | ("M-s e" . consult-isearch) | ||
560 | :map isearch-mode-map | ||
561 | ("M-e" . consult-isearch) ; orig. isearch-edit-string | ||
562 | ("M-s e" . consult-isearch) ; orig. isearch-edit-string | ||
563 | ("M-s l" . consult-line)) ; required by consult-line to detect isearch | ||
564 | :init | ||
565 | (setq register-preview-delay 0 | ||
566 | register-preview-function #'consult-register-format) | ||
567 | (advice-add #'register-preview :override #'consult-register-window) | ||
568 | (setq xref-show-xrefs-function #'consult-xref | ||
569 | xref-show-definitions-function #'consult-xref) | ||
570 | :config | ||
571 | ;; (setq consult-preview-key 'any) | ||
572 | ;; (setq consult-preview-key (kbd "M-p")) | ||
573 | (setq consult-narrow-key "<")) | ||