diff options
author | Case Duckworth | 2023-05-13 23:50:35 -0500 |
---|---|---|
committer | Case Duckworth | 2023-05-13 23:50:35 -0500 |
commit | 832af38380ba5b6a020b034059b4bc5ff7443ded (patch) | |
tree | fce4708280ff964d80a9808ed6826a1f3799e804 /emacs.el | |
parent | uhhhh (diff) | |
download | etc-832af38380ba5b6a020b034059b4bc5ff7443ded.tar.gz etc-832af38380ba5b6a020b034059b4bc5ff7443ded.zip |
uhhh
Diffstat (limited to 'emacs.el')
-rw-r--r-- | emacs.el | 1029 |
1 files changed, 1029 insertions, 0 deletions
diff --git a/emacs.el b/emacs.el new file mode 100644 index 0000000..c6d361b --- /dev/null +++ b/emacs.el | |||
@@ -0,0 +1,1029 @@ | |||
1 | ;;; ~/.emacs -*- mode: emacs-lisp; lexical-binding: t; -*- | ||
2 | ;; by Case Duckworth <acdw@acdw.net> | ||
3 | ;; Bankruptcy 10: "Annoyance" | ||
4 | |||
5 | ;;; Commentary: | ||
6 | |||
7 | ;; This is my Emacs configuration. There are many like it but this | ||
8 | ;; one is mine. | ||
9 | ;; | ||
10 | ;; For the tenth time! | ||
11 | |||
12 | ;;; Code: | ||
13 | |||
14 | (add-hook 'after-init-hook | ||
15 | (lambda () | ||
16 | (load (locate-user-emacs-file "private")))) | ||
17 | |||
18 | ;;; Definitions: | ||
19 | |||
20 | (defun reset-faces () | ||
21 | (dolist (face '(font-lock-regexp-face | ||
22 | font-lock-builtin-face | ||
23 | font-lock-variable-name-face | ||
24 | font-lock-preprocessor-face | ||
25 | font-lock-remove-face | ||
26 | font-lock-delimiter-face | ||
27 | font-lock-label-face | ||
28 | font-lock-operator-face | ||
29 | font-lock-property-face | ||
30 | font-lock-builtin-face | ||
31 | font-lock-number-face | ||
32 | font-lock-keyword-face | ||
33 | font-lock-set-face | ||
34 | font-lock-warning-face | ||
35 | font-lock-punctuation-face | ||
36 | font-lock-constant-face | ||
37 | font-lock-type-face | ||
38 | font-lock-function-name-face | ||
39 | font-lock-reference-face | ||
40 | font-lock-misc-punctuation-face | ||
41 | font-lock-bracket-face)) | ||
42 | (face-spec-set face '((t :foreground unspecified | ||
43 | :background unspecified))))) | ||
44 | |||
45 | (defun electric-pair-local-mode-disable () | ||
46 | "Disable `electric-pair-mode', locally." | ||
47 | (electric-pair-local-mode -1)) | ||
48 | |||
49 | (defun kill-this-buffer (&optional buffer-or-name) | ||
50 | "Kill this buffer, or BUFFER-OR-NAME. | ||
51 | When called interactvely, the user will be prompted when passing | ||
52 | \\[universal-argument]." | ||
53 | (interactive "P") | ||
54 | (cond | ||
55 | ((bufferp buffer-or-name) | ||
56 | (kill-buffer buffer-or-name)) | ||
57 | ((null buffer-or-name) | ||
58 | (kill-current-buffer)) | ||
59 | (:else | ||
60 | (kill-buffer (read-buffer "Kill: " nil :require-match))))) | ||
61 | |||
62 | (defun define-org-capture-template (description &rest args) | ||
63 | "Define an template for `org-capture-templates'. | ||
64 | Will not replace an existing template unless `:force' in ARGS is | ||
65 | non-nil. ARGS is a plist, which in addition to the additional | ||
66 | options `org-capture-templates' accepts (which see), also accepts | ||
67 | the following: `:keys', `:description', `:type', `:target', and | ||
68 | `:template'." | ||
69 | (declare (indent 1)) | ||
70 | (let* ((keys (plist-get args :keys)) | ||
71 | (type (plist-get args :type)) | ||
72 | (target (plist-get args :target)) | ||
73 | (template (plist-get args :template)) | ||
74 | (force (plist-get args :force)) | ||
75 | (template-value | ||
76 | (append | ||
77 | (list description) | ||
78 | (when (or type target template) | ||
79 | (list (or type 'entry) target template)) | ||
80 | (cl-loop for i from 0 below (length args) by 2 | ||
81 | unless (member (nth i args) | ||
82 | '( :keys :description :type | ||
83 | :target :template)) | ||
84 | append (list (nth i args) | ||
85 | (plist-get args (nth i args))))))) | ||
86 | (if (seq-find (lambda (el) (equal (car el) keys)) | ||
87 | org-capture-templates) | ||
88 | (and force | ||
89 | (setf (alist-get keys org-capture-templates nil nil #'equal) | ||
90 | template-value)) | ||
91 | (setf org-capture-templates | ||
92 | (append org-capture-templates | ||
93 | (list (cons keys template-value))))) | ||
94 | org-capture-templates)) | ||
95 | |||
96 | (defun other-window-or-switch-buffer (&optional arg) | ||
97 | "Switch to the other window. | ||
98 | If a window is the only buffer on a frame, switch buffer. When | ||
99 | run with \\[universal-argument], unconditionally switch buffer." | ||
100 | (interactive "P") | ||
101 | (if (or arg (one-window-p)) | ||
102 | (switch-to-buffer (other-buffer) nil t) | ||
103 | (other-window 1))) | ||
104 | |||
105 | (defun cycle-spacing@ (&optional n) | ||
106 | ;; `cycle-spacing' is wildly different in 29.1 over 28. | ||
107 | "Negate N argument on `cycle-spacing'. | ||
108 | That is, with a positive N, deletes newlines as well, leaving -N | ||
109 | spaces. If N is negative, it will not delete newlines and leave | ||
110 | N spaces." | ||
111 | (interactive "*p") | ||
112 | (cycle-spacing (- n))) | ||
113 | |||
114 | (defun first-frame@set-fonts () | ||
115 | (remove-hook 'server-after-make-frame-hook | ||
116 | #'first-frame@set-fonts) | ||
117 | (face-spec-set 'default | ||
118 | `((t :family "Recursive Mono Casual Static" | ||
119 | :height 110))) | ||
120 | (face-spec-set 'variable-pitch | ||
121 | `((t :family "Recursive Sans Casual Static" | ||
122 | :height 1.0))) | ||
123 | ;; Emojis | ||
124 | (cl-loop with ffl = (font-family-list) | ||
125 | for font in '("Noto Emoji" "Noto Color Emoji" | ||
126 | "Segoe UI Emoji" "Apple Color Emoji" | ||
127 | "FreeSans" "FreeMono" "FreeSerif" | ||
128 | "Unifont" "Symbola") | ||
129 | if (member font ffl) | ||
130 | do (set-fontset-font t 'symbol font)) | ||
131 | ;; International fonts | ||
132 | (cl-loop with ffl = (font-family-list) | ||
133 | for (charset . font) | ||
134 | in '((latin . "Noto Sans") | ||
135 | (han . "Noto Sans CJK SC Regular") | ||
136 | (kana . "Noto Sans CJK JP Regular") | ||
137 | (hangul . "Noto Sans CJK KR Regular") | ||
138 | (cjk-misc . "Noto Sans CJK KR Regular") | ||
139 | (khmer . "Noto Sans Khmer") | ||
140 | (lao . "Noto Sans Lao") | ||
141 | (burmese . "Noto Sans Myanmar") | ||
142 | (thai . "Noto Sans Thai") | ||
143 | (ethiopic . "Noto Sans Ethiopic") | ||
144 | (hebrew . "Noto Sans Hebrew") | ||
145 | (arabic . "Noto Sans Arabic") | ||
146 | (gujarati . "Noto Sans Gujarati") | ||
147 | (devanagari . "Noto Sans Devanagari") | ||
148 | (kannada . "Noto Sans Kannada") | ||
149 | (malayalam . "Noto Sans Malayalam") | ||
150 | (oriya . "Noto Sans Oriya") | ||
151 | (sinhala . "Noto Sans Sinhala") | ||
152 | (tamil . "Noto Sans Tamil") | ||
153 | (telugu . "Noto Sans Telugu") | ||
154 | (tibetan . "Noto Sans Tibetan")) | ||
155 | if (member font ffl) | ||
156 | do (set-fontset-font t charset font)) | ||
157 | ;; XXX: tab-bar does a weird thing, so i set it up here.... | ||
158 | (setopt tab-bar-show t) | ||
159 | (tab-bar-mode)) | ||
160 | |||
161 | (defun renz/sort-by-alpha-length (elems) | ||
162 | "Sort ELEMS first alphabetically, then by length." | ||
163 | (sort elems (lambda (c1 c2) | ||
164 | (or (string-version-lessp c1 c2) | ||
165 | (< (length c1) (length c2)))))) | ||
166 | |||
167 | (defun renz/sort-by-history (elems) | ||
168 | "Sort ELEMS by minibuffer history. | ||
169 | Use `mct-sort-sort-by-alpha-length' if no history is available." | ||
170 | (if-let ((hist (and (not (eq minibuffer-history-variable t)) | ||
171 | (symbol-value minibuffer-history-variable)))) | ||
172 | (minibuffer--sort-by-position hist elems) | ||
173 | (renz/sort-by-alpha-length elems))) | ||
174 | |||
175 | (defun renz/completion-category () | ||
176 | "Return completion category." | ||
177 | (when-let ((window (active-minibuffer-window))) | ||
178 | (with-current-buffer (window-buffer window) | ||
179 | (completion-metadata-get | ||
180 | (completion-metadata (buffer-substring-no-properties | ||
181 | (minibuffer-prompt-end) | ||
182 | (max (minibuffer-prompt-end) (point))) | ||
183 | minibuffer-completion-table | ||
184 | minibuffer-completion-predicate) | ||
185 | 'category)))) | ||
186 | |||
187 | (defun renz/sort-multi-category (elems) | ||
188 | "Sort ELEMS per completion category." | ||
189 | (pcase (renz/completion-category) | ||
190 | ('nil elems) ; no sorting | ||
191 | ('kill-ring elems) | ||
192 | ('project-file (renz/sort-by-alpha-length elems)) | ||
193 | (_ (renz/sort-by-history elems)))) | ||
194 | |||
195 | (defvar no-tabs-modes '(emacs-lisp-mode | ||
196 | lisp-mode | ||
197 | scheme-mode | ||
198 | python-mode | ||
199 | haskell-mode) | ||
200 | "Modes /not/ to indent with tabs.") | ||
201 | |||
202 | (defun indent-tabs-mode-maybe () | ||
203 | (if (apply #'derived-mode-p no-tabs-modes) | ||
204 | (indent-tabs-mode -1) | ||
205 | (indent-tabs-mode 1))) | ||
206 | |||
207 | (define-minor-mode truncate-lines-mode | ||
208 | "Buffer-local mode to toggle `truncate-lines'." | ||
209 | :lighter "" | ||
210 | (setq-local truncate-lines truncate-lines-mode)) | ||
211 | |||
212 | ;;; Region or buffer stuff | ||
213 | |||
214 | (defun call-with-region-or-buffer (fn &rest _r) | ||
215 | "Call function FN with current region or buffer. | ||
216 | Good to use for :around advice." | ||
217 | (if (region-active-p) | ||
218 | (funcall fn (region-beginning) (region-end)) | ||
219 | (funcall fn (point-min) (point-max)))) | ||
220 | |||
221 | (defun delete-trailing-whitespace-except-current-line () | ||
222 | (save-excursion | ||
223 | (delete-trailing-whitespace (point-min) | ||
224 | (line-beginning-position)) | ||
225 | (delete-trailing-whitespace (line-end-position) | ||
226 | (point-max)))) | ||
227 | |||
228 | (defun create-missing-directories () | ||
229 | "Automatically create missing directories." | ||
230 | (let ((target-dir (file-name-directory buffer-file-name))) | ||
231 | (unless (file-exists-p target-dir) | ||
232 | (make-directory target-dir :parents)))) | ||
233 | |||
234 | |||
235 | (defun vc-remote-off () | ||
236 | "Turn VC off when remote." | ||
237 | (when (file-remote-p (buffer-file-name)) | ||
238 | (setq-local vc-handled-backends nil))) | ||
239 | |||
240 | (defun +titlecase-sentence-style-dwim (&optional arg) | ||
241 | "Titlecase a sentence. | ||
242 | With prefix ARG, toggle the value of | ||
243 | `titlecase-downcase-sentences' before sentence-casing." | ||
244 | (interactive "P") | ||
245 | (let ((titlecase-downcase-sentences (if arg (not titlecase-downcase-sentences) | ||
246 | titlecase-downcase-sentences))) | ||
247 | (titlecase-dwim 'sentence))) | ||
248 | |||
249 | (defun +titlecase-org-headings () | ||
250 | (interactive) | ||
251 | (require 'org) | ||
252 | (save-excursion | ||
253 | (goto-char (point-min)) | ||
254 | ;; See also `org-map-tree'. I'm not using that function because I want to | ||
255 | ;; skip the first headline. A better solution would be to patch | ||
256 | ;; `titlecase-line' to ignore org-mode metadata (TODO cookies, tags, etc). | ||
257 | (let ((level (funcall outline-level)) | ||
258 | (org-special-ctrl-a/e t)) | ||
259 | (while (and (progn (outline-next-heading) | ||
260 | (> (funcall outline-level) level)) | ||
261 | (not (eobp))) | ||
262 | (titlecase-region (progn (org-beginning-of-line) (point)) | ||
263 | (progn (org-end-of-line) (point))))))) | ||
264 | |||
265 | (defcustom browse-url-safe-browser-functions nil | ||
266 | "\"Safe\" browser functions." | ||
267 | :type '(repeat-function)) | ||
268 | |||
269 | (defun browse-url-browser-function-safe-p (fn) | ||
270 | "Return t if FN is a \"safe\" browser function." | ||
271 | (memq f (append browse-url-safe-browser-functions | ||
272 | (mapcar (lambda (i) | ||
273 | (plist-get (cdr i) :value)) | ||
274 | (seq-filter (lambda (i) | ||
275 | (eq (car i) 'function-item)) | ||
276 | (cdr (get 'browse-url-browser-function | ||
277 | 'custom-type))))))) | ||
278 | |||
279 | (put 'browse-url-browser-function 'safe-local-variable | ||
280 | 'browse-url-browser-function-safe-p) | ||
281 | |||
282 | |||
283 | ;;; Packages: | ||
284 | |||
285 | (require 'package) | ||
286 | (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) | ||
287 | (package-initialize) | ||
288 | |||
289 | (defun ensure-package (pkg &optional localp) | ||
290 | "Esnure PKG is installed from repositories. | ||
291 | If LOCALP is t, add ~/src/PKG.el to `load-path'. | ||
292 | If LOCALP is a string, add that directory to the `load-path'." | ||
293 | (cond | ||
294 | ((stringp localp) | ||
295 | (and (file-exists-p localp) | ||
296 | (add-to-list 'load-path localp))) | ||
297 | (localp | ||
298 | (ensure-package pkg | ||
299 | (expand-file-name | ||
300 | (format "~/src/%s.el" | ||
301 | (symbol-name pkg))))) | ||
302 | (:else | ||
303 | (unless (package-installed-p pkg) | ||
304 | (unless (ignore-errors (package-install pkg)) | ||
305 | (package-refresh-contents) | ||
306 | (package-install pkg)))))) | ||
307 | |||
308 | ;; Install packages here. Acutal configuration is done in the Configuration | ||
309 | ;; section. | ||
310 | (ensure-package 'consult) | ||
311 | (ensure-package 'marginalia) | ||
312 | (ensure-package 'visual-fill-column) | ||
313 | (ensure-package 'adaptive-wrap) | ||
314 | (ensure-package 'geiser) | ||
315 | (when (executable-find "csi") | ||
316 | (ensure-package 'geiser-chicken)) | ||
317 | (ensure-package 'avy) | ||
318 | (ensure-package 'zzz-to-char) | ||
319 | (ensure-package 'hungry-delete) | ||
320 | (ensure-package 'undohist) | ||
321 | (ensure-package 'jinx) | ||
322 | (ensure-package 'markdown-mode) | ||
323 | (ensure-package 'anzu) | ||
324 | |||
325 | ;; Local packages | ||
326 | (ensure-package 'scule t) | ||
327 | (ensure-package 'frowny t) | ||
328 | (ensure-package 'hippie-completing-read t) | ||
329 | (ensure-package 'mode-line-bell t) | ||
330 | (ensure-package 'titlecase t) | ||
331 | (ensure-package 'jabber t) | ||
332 | |||
333 | ;;; Jabber | ||
334 | |||
335 | (use-package jabber | ||
336 | :load-path "~/src/jabber.el" | ||
337 | :defer t | ||
338 | :bind-keymap (("C-c j" . jabber-global-keymap)) | ||
339 | :preface nil | ||
340 | (setq-default jabber-chat-buffer-format "*%n*" | ||
341 | jabber-browse-buffer-format "*%n*" | ||
342 | jabber-groupchat-buffer-format "*%n*" | ||
343 | jabber-muc-private-buffer-format "*%n*") | ||
344 | :custom-face | ||
345 | (jabber-activity-face ((t :inherit jabber-chat-prompt-foreign | ||
346 | :foreground unspecified | ||
347 | :weight normal))) | ||
348 | (jabber-activity-personal-face ((t :inherit jabber-chat-prompt-local | ||
349 | :foreground unspecified | ||
350 | :weight bold))) | ||
351 | (jabber-chat-prompt-local ((t :inherit minibuffer-prompt | ||
352 | :foreground unspecified | ||
353 | :weight normal | ||
354 | :slant italic))) | ||
355 | (jabber-chat-prompt-foreign ((t :inherit warning | ||
356 | :foreground unspecified | ||
357 | :weight normal))) | ||
358 | (jabber-chat-prompt-system ((t :inherit font-lock-doc-face | ||
359 | :foreground unspecified))) | ||
360 | (jabber-rare-time-face ((t :inherit font-lock-comment-face | ||
361 | :foreground unspecified | ||
362 | :underline nil))) | ||
363 | :config | ||
364 | (require 'jabber-httpupload nil t) | ||
365 | (setopt jabber-auto-reconnect t | ||
366 | jabber-last-read-marker "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" | ||
367 | jabber-muc-decorate-presence-patterns | ||
368 | '(("\\( enters the room ([^)]+)\\| has left the chatroom\\)$" . nil) | ||
369 | ("Mode #.*" . jabber-muc-presence-dim) | ||
370 | ("." . jabber-muc-presence-dim)) | ||
371 | jabber-activity-make-strings #'jabber-activity-make-strings-shorten | ||
372 | jabber-rare-time-format | ||
373 | (format " - - - - - %%H:%d %%F" | ||
374 | (let ((min (string-to-number (format-time-string "%M")))) | ||
375 | (* 5 (floor min 5)))) | ||
376 | jabber-muc-header-line-format '(" " jabber-muc-topic)) | ||
377 | |||
378 | (setopt jabber-groupchat-prompt-format "%n. " | ||
379 | jabber-chat-local-prompt-format "%n. " | ||
380 | jabber-chat-foreign-prompt-format "%n. " | ||
381 | jabber-muc-private-foreign-prompt-format "%g/%n. ") | ||
382 | |||
383 | (keymap-global-set "C-c C-SPC" #'jabber-activity-switch-to) | ||
384 | (map-keymap (lambda (key command) | ||
385 | (define-key jabber-global-keymap (vector (+ key #x60)) command)) | ||
386 | jabber-global-keymap) | ||
387 | (keymap-global-set "C-x C-j" #'dired-jump) | ||
388 | |||
389 | (add-hook 'jabber-post-connect-hooks #'jabber-enable-carbons) | ||
390 | (remove-hook 'jabber-alert-muc-hooks 'jabber-muc-echo) | ||
391 | (remove-hook 'jabber-alert-presence-hooks 'jabber-presence-echo) | ||
392 | (add-hook 'jabber-chat-mode-hook 'visual-line-mode) | ||
393 | (add-hook 'jabber-chat-mode-hook (defun jabber-no-position () | ||
394 | (setq-local mode-line-position nil))) | ||
395 | |||
396 | (add-hook 'jabber-alert-muc-hooks | ||
397 | (defun jabber@highlight-acdw (&optional _ _ buf _ _) | ||
398 | (when buf | ||
399 | (with-current-buffer buf | ||
400 | (let ((regexp (rx word-boundary | ||
401 | "acdw" ; maybe get from the config? | ||
402 | word-boundary))) | ||
403 | (hi-lock-unface-buffer regexp) | ||
404 | (highlight-regexp regexp 'jabber-chat-prompt-local)))))) | ||
405 | |||
406 | (when (fboundp 'jabber-chat-update-focus) | ||
407 | (add-hook 'window-configuration-change-hook #'jabber-chat-update-focus))) | ||
408 | |||
409 | |||
410 | ;;; Configuration: | ||
411 | |||
412 | (setopt custom-file (locate-user-emacs-file "custom.el")) | ||
413 | (load custom-file :noerror) | ||
414 | |||
415 | ;;; General keybinding changes | ||
416 | |||
417 | (keymap-global-set "M-o" #'other-window-or-switch-buffer) | ||
418 | (keymap-global-set "M-SPC" #'cycle-spacing@) | ||
419 | (keymap-global-set "M-u" #'universal-argument) | ||
420 | (keymap-set universal-argument-map "M-u" #'universal-argument-more) | ||
421 | |||
422 | ;;; Theme | ||
423 | |||
424 | (if (daemonp) | ||
425 | (add-hook 'server-after-make-frame-hook #'first-frame@set-fonts) | ||
426 | (run-with-idle-timer 1 nil #'first-frame@set-fonts)) | ||
427 | |||
428 | (tool-bar-mode -1) | ||
429 | |||
430 | (setopt modus-themes2-bold-constructs nil | ||
431 | modus-themes-italic-constructs t | ||
432 | modus-themes-variable-pitch-ui t) | ||
433 | |||
434 | (add-hook 'modus-themes-after-load-theme-hook #'reset-faces) | ||
435 | |||
436 | (load-theme 'modus-vivendi :no-confirm :no-enable) | ||
437 | (load-theme 'modus-operandi :no-confirm) | ||
438 | |||
439 | (add-hook 'text-mode-hook #'visual-line-mode) | ||
440 | (add-hook 'prog-mode-hook #'auto-fill-mode) | ||
441 | (add-hook 'prog-mode-hook #'display-fill-column-indicator-mode) | ||
442 | |||
443 | ;;; Mode line | ||
444 | |||
445 | (defvar mode-line-position | ||
446 | '("" | ||
447 | (:propertize | ||
448 | ("" | ||
449 | (:eval (if line-number-mode "%3l" "")) | ||
450 | (:eval (if column-number-mode | ||
451 | (if column-number-indicator-zero-based | ||
452 | "/%2c" | ||
453 | "/%2C") | ||
454 | ""))) | ||
455 | display (min-width (3.0))) | ||
456 | (:propertize (" [" (-3 "%p") "] ") | ||
457 | display (min-width (6.0))))) | ||
458 | |||
459 | (setopt mode-line-format | ||
460 | '(("%e" | ||
461 | mode-line-front-space | ||
462 | (:propertize ("" | ||
463 | mode-line-client | ||
464 | mode-line-modified | ||
465 | mode-line-remote) | ||
466 | display (min-width (3.0))) | ||
467 | " " | ||
468 | mode-line-buffer-identification | ||
469 | (vc-mode (" (" (:eval (string-trim vc-mode)) ")")) | ||
470 | " " | ||
471 | (mode-line-position mode-line-position) | ||
472 | mode-line-modes | ||
473 | mode-line-misc-info | ||
474 | mode-line-end-spaces))) | ||
475 | |||
476 | ;; Remove modes from mode-line | ||
477 | (dolist (minor-mode '(frowny-mode | ||
478 | whitespace-mode | ||
479 | hungry-delete-mode)) | ||
480 | (setf (alist-get minor-mode minor-mode-alist) (list "")) | ||
481 | (add-hook (intern (format "%s-hook" minor-mode)) | ||
482 | (lambda () | ||
483 | (setf (alist-get minor-mode minor-mode-alist) (list ""))))) | ||
484 | |||
485 | ;;; Completion & minibuffer | ||
486 | |||
487 | (fido-vertical-mode) | ||
488 | (minibuffer-depth-indicate-mode) | ||
489 | |||
490 | (setopt completion-auto-help (not icomplete-mode) | ||
491 | completion-auto-select 'second-tab | ||
492 | completions-header-format nil | ||
493 | completions-max-height 12 | ||
494 | completions-format 'one-column | ||
495 | completion-styles '(basic partial-completion emacs22 flex) | ||
496 | completion-ignore-case t | ||
497 | read-buffer-completion-ignore-case t | ||
498 | read-file-name-completion-ignore-case t | ||
499 | completions-detailed t | ||
500 | enable-recursive-minibuffers t | ||
501 | file-name-shadow-properties '(invisible t intangible t) | ||
502 | minibuffer-eldef-shorten-default t | ||
503 | minibuffer-prompt-properties '( read-only t | ||
504 | cursor-intangible t | ||
505 | face minibuffer-prompt) | ||
506 | window-resize-pixelwise t | ||
507 | frame-resize-pixelwise t) | ||
508 | |||
509 | (add-hook 'completion-list-mode-hook #'truncate-lines-mode) | ||
510 | (add-hook 'minibuffer-setup-hook #'truncate-lines-mode) | ||
511 | |||
512 | ;; Up/down when completing in the minibuffer | ||
513 | ;; (define-key minibuffer-local-map (kbd "C-p") #'minibuffer-previous-completion) | ||
514 | ;; (define-key minibuffer-local-map (kbd "C-n") #'minibuffer-next-completion) | ||
515 | |||
516 | ;; Up/down when competing in a normal buffer | ||
517 | ;; (define-key completion-in-region-mode-map (kbd "C-p") #'minibuffer-previous-completion) | ||
518 | ;; (define-key completion-in-region-mode-map (kbd "C-n") #'minibuffer-next-completion) | ||
519 | |||
520 | (setopt completions-sort #'renz/sort-multi-category) | ||
521 | |||
522 | (setopt tab-always-indent 'complete) | ||
523 | |||
524 | (file-name-shadow-mode) | ||
525 | (minibuffer-electric-default-mode) | ||
526 | |||
527 | (scroll-bar-mode -1) | ||
528 | (menu-bar-mode -1) | ||
529 | |||
530 | (add-hook 'prog-mode-hook #'indent-tabs-mode-maybe) | ||
531 | |||
532 | (setopt electric-pair-skip-whitespace 'chomp) | ||
533 | (electric-pair-mode) | ||
534 | |||
535 | (setopt sh-basic-offset tab-width) | ||
536 | |||
537 | (keymap-set emacs-lisp-mode-map "C-c C-c" #'eval-defun) | ||
538 | (keymap-set emacs-lisp-mode-map "C-c C-k" #'eval-buffer) | ||
539 | (keymap-set lisp-interaction-mode-map "C-c C-c" #'eval-defun) | ||
540 | (keymap-set lisp-interaction-mode-map "C-c C-k" #'eval-buffer) | ||
541 | |||
542 | (advice-add 'indent-region :around #'call-with-region-or-buffer) | ||
543 | (advice-add 'tabify :around #'call-with-region-or-buffer) | ||
544 | (advice-add 'untabify :around #'call-with-region-or-buffer) | ||
545 | |||
546 | (with-eval-after-load 'scheme | ||
547 | (keymap-unset scheme-mode-map "M-o" t) | ||
548 | ;; Comparse "keywords" --- CHICKEN (http://wiki.call-cc.org/eggref/5/comparse) | ||
549 | (put 'sequence* 'scheme-indent-function 1) | ||
550 | (put 'satisfies 'scheme-indent-function 1) | ||
551 | (add-hook 'scheme-mode-hook #'geiser-mode)) | ||
552 | (with-eval-after-load 'geiser-mode | ||
553 | (keymap-set geiser-mode-map "C-c C-k" #'geiser-eval-buffer-and-go) | ||
554 | (keymap-unset geiser-mode-map "C-." t)) | ||
555 | |||
556 | |||
557 | (with-eval-after-load 'visual-fill-column | ||
558 | (setopt visual-fill-column-center-text t | ||
559 | visual-fill-column-width (+ fill-column 2)) | ||
560 | (advice-add 'text-scale-adjust :after #'visual-fill-column-adjust)) | ||
561 | (add-hook 'visual-line-mode-hook #'visual-fill-column-mode) | ||
562 | (add-hook 'visual-line-mode-hook #'adaptive-wrap-prefix-mode) | ||
563 | |||
564 | (setopt major-mode | ||
565 | (lambda () ; guess major mode from buffer name | ||
566 | (unless buffer-file-name | ||
567 | (let ((buffer-file-name (buffer-name))) | ||
568 | (set-auto-mode))))) | ||
569 | |||
570 | ;; Dialogs | ||
571 | (unless (boundp 'use-short-answers) | ||
572 | (fset 'yes-or-no-p 'y-or-n-p)) | ||
573 | |||
574 | (setopt read-answer-short t | ||
575 | use-dialog-box nil | ||
576 | use-file-dialog nil | ||
577 | use-short-answers t) | ||
578 | |||
579 | (require 'savehist) | ||
580 | (setopt history-length 1024 | ||
581 | history-delete-duplicates t | ||
582 | ;; savehist-file (etc/ "savehist.el") | ||
583 | savehist-save-minibuffer-history t | ||
584 | savehist-autosave-interval 30) | ||
585 | (savehist-mode) | ||
586 | |||
587 | ;; Killing and yanking | ||
588 | (setopt kill-do-not-save-duplicates t | ||
589 | kill-read-only-ok t | ||
590 | ;; XXX: This setting causes an error message the first time it's | ||
591 | ;; called: "Selection owner couldn't convert: TIMESTAMP". I have | ||
592 | ;; absolutely no idea why I get this error, but it's generated in | ||
593 | ;; `x_get_foreign_selection'. I also can't inhibit the message or | ||
594 | ;; do anything else with it, so for now, I'll just live with the | ||
595 | ;; message. | ||
596 | save-interprogram-paste-before-kill t | ||
597 | yank-pop-change-selection t) | ||
598 | (delete-selection-mode) | ||
599 | |||
600 | ;; Notifying the user | ||
601 | (setopt echo-keystrokes 0.01 | ||
602 | ring-bell-function #'ignore) | ||
603 | |||
604 | ;; Point and mark | ||
605 | (setopt set-mark-command-repeat-pop t) | ||
606 | |||
607 | ;; The system | ||
608 | (setopt read-process-output-max (* 10 1024 1024)) | ||
609 | |||
610 | ;; Startup | ||
611 | (setopt inhibit-startup-screen t | ||
612 | initial-buffer-choice t | ||
613 | initial-scratch-message nil) | ||
614 | |||
615 | (define-advice startup-echo-area-message (:override ()) | ||
616 | (if (get-buffer "*Warnings*") | ||
617 | ";_;" | ||
618 | "^_^")) | ||
619 | |||
620 | ;; Text editing | ||
621 | (setopt fill-column 80 | ||
622 | sentence-end-double-space nil | ||
623 | tab-width 8 | ||
624 | tab-always-indent 'complete) | ||
625 | (global-so-long-mode) | ||
626 | |||
627 | (setopt show-paren-delay 0.01 | ||
628 | show-paren-style 'parenthesis | ||
629 | show-paren-when-point-in-periphery t | ||
630 | show-paren-when-point-inside-paren t) | ||
631 | (show-paren-mode) | ||
632 | |||
633 | |||
634 | ;; Encodings | ||
635 | (set-language-environment "UTF-8") | ||
636 | (setopt buffer-file-coding-system 'utf-8-unix | ||
637 | coding-system-for-read 'utf-8-unix | ||
638 | coding-system-for-write 'utf-8-unix | ||
639 | default-process-coding-system '(utf-8-unix . utf-8-unix) | ||
640 | locale-coding-system 'utf-8-unix) | ||
641 | (set-charset-priority 'unicode) | ||
642 | (prefer-coding-system 'utf-8-unix) | ||
643 | (set-default-coding-systems 'utf-8-unix) | ||
644 | (set-terminal-coding-system 'utf-8-unix) | ||
645 | (set-keyboard-coding-system 'utf-8-unix) | ||
646 | (pcase system-type | ||
647 | ((or 'ms-dos 'windows-nt) | ||
648 | (set-clipboard-coding-system 'utf-16-le) | ||
649 | (set-selection-coding-system 'utf-16-le)) | ||
650 | (_ | ||
651 | (set-selection-coding-system 'utf-8) | ||
652 | (set-clipboard-coding-system 'utf-8))) | ||
653 | |||
654 | |||
655 | ;; Files | ||
656 | (setopt auto-revert-verbose nil | ||
657 | global-auto-revert-non-file-buffers t | ||
658 | create-lockfiles nil | ||
659 | find-file-visit-truename t | ||
660 | mode-require-final-newline t | ||
661 | view-read-only t | ||
662 | save-silently t) | ||
663 | (global-auto-revert-mode) | ||
664 | |||
665 | (setopt auto-save-default nil | ||
666 | auto-save-interval 1 | ||
667 | auto-save-no-message t | ||
668 | auto-save-timeout 1 | ||
669 | auto-save-visited-interval 1 | ||
670 | remote-file-name-inhibit-auto-save-visited t) | ||
671 | (add-to-list 'auto-save-file-name-transforms | ||
672 | `(".*" ,(locate-user-emacs-file "auto-save/") t)) | ||
673 | (auto-save-visited-mode) | ||
674 | |||
675 | (setopt backup-by-copying t | ||
676 | version-control t | ||
677 | kept-new-versions 8 | ||
678 | kept-old-versions 8 | ||
679 | delete-old-versions t) | ||
680 | (setq-default backup-directory-alist | ||
681 | `(("^/dev/shm" . nil) | ||
682 | ("^/tmp" . nil) | ||
683 | (,(getenv "XDG_RUNTIME_DIR") . nil) | ||
684 | ("." . ,(locate-user-emacs-file "backup")))) | ||
685 | |||
686 | (require 'recentf) | ||
687 | (setopt | ||
688 | recentf-max-menu-items 500 | ||
689 | recentf-max-saved-items nil ; Save the whole list | ||
690 | recentf-auto-cleanup 'mode | ||
691 | recentf-case-fold-search t) | ||
692 | ;; (add-to-list 'recentf-exclude etc/) | ||
693 | (add-to-list 'recentf-exclude "-autoloads.el\\'") | ||
694 | (add-hook 'buffer-list-update-hook #'recentf-track-opened-file) | ||
695 | (add-hook 'after-save-hook #'recentf-save-list) | ||
696 | (recentf-mode) | ||
697 | |||
698 | (require 'saveplace) | ||
699 | (setopt | ||
700 | save-place-forget-unreadable-files (eq system-type | ||
701 | 'gnu/linux)) | ||
702 | (save-place-mode) | ||
703 | |||
704 | (require 'uniquify) | ||
705 | (setq uniquify-after-kill-buffer-p t | ||
706 | uniquify-buffer-name-style 'forward | ||
707 | uniquify-ignore-buffers-re "^\\*" | ||
708 | uniquify-separator path-separator) | ||
709 | |||
710 | (setq-local vc-follow-symlinks t | ||
711 | vc-make-backup-files t) | ||
712 | |||
713 | ;; Whitespace | ||
714 | (require 'whitespace) | ||
715 | (setopt whitespace-style | ||
716 | '(face trailing tabs tab-mark)) | ||
717 | (global-whitespace-mode) | ||
718 | (add-hook 'before-save-hook #'delete-trailing-whitespace-except-current-line) | ||
719 | |||
720 | ;; Native compilation | ||
721 | (setopt native-comp-async-report-warnings-errors 'silent | ||
722 | native-comp-deferred-compilation t | ||
723 | native-compile-target-directory | ||
724 | (locate-user-emacs-file "eln")) | ||
725 | (when (boundp 'native-comp-eln-load-path) | ||
726 | (add-to-list 'native-comp-eln-load-path native-compile-target-directory)) | ||
727 | (when (fboundp 'startup-redirect-eln-cache) | ||
728 | (startup-redirect-eln-cache native-compile-target-directory)) | ||
729 | |||
730 | (global-goto-address-mode) | ||
731 | |||
732 | ;; Winner | ||
733 | (winner-mode) | ||
734 | |||
735 | ;;; Hooks | ||
736 | (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) | ||
737 | (add-hook 'find-file-not-found-functions #'create-missing-directories) | ||
738 | (add-hook 'find-file-hook #'vc-remote-off) | ||
739 | (add-hook 'dired-mode-hook #'hl-line-mode) | ||
740 | (add-hook 'org-agenda-mode-hook #'hl-line-mode) | ||
741 | |||
742 | ;;; Tab bar | ||
743 | |||
744 | (defun tab-bar-end-space () | ||
745 | `((end menu-item " " ignore))) | ||
746 | |||
747 | (add-to-list 'tab-bar-format 'tab-bar-format-align-right :append) | ||
748 | (add-to-list 'tab-bar-format 'tab-bar-format-global :append) | ||
749 | (add-to-list 'tab-bar-format 'tab-bar-end-space :append) | ||
750 | ;;(setopt tab-bar-show t) | ||
751 | ;;(tab-bar-mode) ; done after setting fonts | ||
752 | |||
753 | ;;; Org mode | ||
754 | |||
755 | (keymap-global-set "C-c a" #'org-agenda) | ||
756 | (keymap-global-set "C-c c" #'org-capture) | ||
757 | (setopt org-clock-clocked-in-display 'frame-title | ||
758 | org-clock-frame-title-format | ||
759 | '("%b" " - " (t org-mode-line-string)) | ||
760 | org-tags-column (- (- fill-column 3)) | ||
761 | org-log-into-drawer t | ||
762 | org-clock-into-drawer t) | ||
763 | |||
764 | ;;; Spelling | ||
765 | |||
766 | (defun list-of-strings-p (x) | ||
767 | "Is X a list of strings?" | ||
768 | (and x | ||
769 | (listp x) | ||
770 | (cl-every #'stringp x))) | ||
771 | |||
772 | (put 'ispell-local-words 'safe-local-variable | ||
773 | 'list-of-strings-p) | ||
774 | |||
775 | (add-hook 'text-mode-hook #'jinx-mode) | ||
776 | (with-eval-after-load 'jinx | ||
777 | (keymap-set jinx-mode-map "M-$" #'jinx-correct) | ||
778 | (keymap-set jinx-mode-map "C-M-$" #'jinx-languages)) | ||
779 | |||
780 | ;;; org-return-dwim | ||
781 | ;; https://github.com/alphapapa/unpackaged.el, | ||
782 | ;; http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/ | ||
783 | (defun org-return-dwim (&optional arg) | ||
784 | "A helpful replacement for `org-return'. | ||
785 | When called interactively with \\[universal-argument], call `org-return' | ||
786 | itself. Other values of ARG will call `newline' with that ARG." | ||
787 | (interactive "P") | ||
788 | ;; Auto-fill if enabled | ||
789 | (when auto-fill-function | ||
790 | (dolist (func (ensure-list auto-fill-function)) | ||
791 | (funcall func))) | ||
792 | (cl-letf* ((el (org-element-at-point)) | ||
793 | ((symbol-function 'el-child-of) | ||
794 | (lambda (&rest types) | ||
795 | (org-element-lineage el types t)))) | ||
796 | (cond ; Figure out what we're going to do | ||
797 | (arg ; Handle prefix ARG | ||
798 | (pcase arg | ||
799 | ('(4) (org-return t nil t)) | ||
800 | (_ (newline arg t)))) | ||
801 | ((and org-return-follows-link ; Open a link | ||
802 | (el-child-of 'link)) | ||
803 | (org-open-at-point-global)) | ||
804 | ((org-at-heading-p) ; Open a paragraph after a heading | ||
805 | (let ((heading-start (org-entry-beginning-position))) | ||
806 | (goto-char (org-entry-end-position)) | ||
807 | (cond ((and (org-at-heading-p) ; Entry is only a heading | ||
808 | (= heading-start (org-entry-beginning-position))) | ||
809 | (end-of-line) | ||
810 | (newline 2)) | ||
811 | (:else ; Entry is more than a heading | ||
812 | (forward-line -1) | ||
813 | (end-of-line) | ||
814 | (when (org-at-heading-p) | ||
815 | ;; Open a paragraph | ||
816 | (forward-line) | ||
817 | (newline) | ||
818 | (forward-line -1)) | ||
819 | (while (not (looking-back "\\(?:[[:blank:]]?\n\\)\\{3\\}" nil)) | ||
820 | (newline)) | ||
821 | (forward-line -1))))) | ||
822 | ((org-at-item-checkbox-p) ; Insert a new checkbox item | ||
823 | (end-of-line) | ||
824 | (org-insert-todo-heading nil)) | ||
825 | ((org-in-item-p) ; Insert a new list item | ||
826 | (let* ((context (org-element-context el)) | ||
827 | (first-item-p (eq 'plain-list (car context))) | ||
828 | (itemp (eq 'item (car context))) | ||
829 | (emptyp (or | ||
830 | ;; This (regular) list item is empty | ||
831 | (eq (org-element-property :contents-begin context) | ||
832 | (org-element-property :contents-end context)) | ||
833 | ;; This (definition) list item is empty | ||
834 | (looking-at " *::"))) | ||
835 | (item-child-p (el-child-of 'item))) | ||
836 | (cond ((and itemp emptyp) | ||
837 | ;; This test has to be here even though it's the same as the | ||
838 | ;; :else clause, because an item that's empty will also satisfy | ||
839 | ;; the next clause. | ||
840 | (delete-region (line-beginning-position) (line-end-position)) | ||
841 | (newline)) | ||
842 | ((or first-item-p | ||
843 | (and itemp (not emptyp)) | ||
844 | item-child-p) | ||
845 | (org-end-of-item) | ||
846 | (org-insert-item)) | ||
847 | (:else | ||
848 | (delete-region (line-beginning-position) (line-end-position)) | ||
849 | (newline))))) | ||
850 | ((and (fboundp 'org-inlinetask-in-task-p) ; Just return for inline tasks | ||
851 | (org-inlinetask-in-task-p)) | ||
852 | (org-return)) | ||
853 | ((org-at-table-p) ; Insert a new table row | ||
854 | (cond ((save-excursion ; Empty row: end the table | ||
855 | (beginning-of-line) | ||
856 | (cl-loop with end = (line-end-position) | ||
857 | for cell = (org-element-table-cell-parser) | ||
858 | always (eq (org-element-property :contents-begin cell) | ||
859 | (org-element-property :contents-end cell)) | ||
860 | while (re-search-forward "|" end t))) | ||
861 | (delete-region (line-beginning-position) (line-end-position)) | ||
862 | (org-return)) | ||
863 | (:else ; Non-empty row | ||
864 | (org-return)))) | ||
865 | (:else ; Something else | ||
866 | (org-return))))) | ||
867 | |||
868 | (defun org-table-copy-down|org-return-dwim (&optional n) | ||
869 | "Call `org-table-copy-down' or `+org-return' depending on context." | ||
870 | (interactive "P") | ||
871 | (if (org-table-check-inside-data-field 'noerror) | ||
872 | (org-table-copy-down (or n 1)) | ||
873 | (org-return-dwim n))) | ||
874 | |||
875 | (with-eval-after-load 'org | ||
876 | (keymap-set org-mode-map "RET" #'org-return-dwim) | ||
877 | (keymap-set org-mode-map "S-RET" #'org-table-copy-down|org-return-dwim)) | ||
878 | |||
879 | ;;; Copy rich text to the keyboard | ||
880 | |||
881 | (defcustom clipboard-html-copy-program | ||
882 | (if (or (equal "wayland" | ||
883 | (getenv "XDG_SESSION_TYPE")) | ||
884 | (getenv "WAYLAND_DISPLAY")) | ||
885 | '("wl-copy" "-t" "text/html") | ||
886 | '("xclip" "-t" "text/html" "-selection" "clipboard")) | ||
887 | "Program to use to copy HTML to the clipboard. | ||
888 | Should be a list of strings---the command line. | ||
889 | Defaults to 'wl-copy' on wayland and 'xclip' on Xorg." | ||
890 | :type '(repeat string)) | ||
891 | |||
892 | ;; Thanks to Oleh Krehel: | ||
893 | ;; https://emacs.stackexchange.com/questions/54292/copy-results-of-org-export-directly-to-clipboard | ||
894 | ;; So. Emacs can't do this itself because it doesn't support sending clipboard | ||
895 | ;; or selection contents as text/html. We have to use xclip instead. | ||
896 | ;; (defun org-to-html-to-clipboard (&rest org-export-args) | ||
897 | ;; "Export current org buffer to HTML, then copy it to the clipboard. | ||
898 | ;; ORG-EXPORT-ARGS are passed to `org-export-to-file'." | ||
899 | ;; (let ((f (make-temp-file "org-html-export"))) | ||
900 | ;; (apply #'org-export-to-file 'html f org-export-args) | ||
901 | ;; (start-process "xclip" " *xclip*" | ||
902 | ;; "xclip" "-verbose" "-i" f | ||
903 | ;; "-t" "text/html" "-selection" "clipboard") | ||
904 | ;; (message "HTML pasted to clipboard."))) | ||
905 | |||
906 | (defun org-export-html-copy (&rest org-export-args) | ||
907 | "Export current org buffer to HTML and copy to clipboard as rich text. | ||
908 | ORG-EXPORT-ARGS are passed to `org-export-to-buffer'." | ||
909 | (let ((buf (generate-new-buffer "*org-html-clipboard*" t))) | ||
910 | (apply #'org-export-to-buffer 'html buf org-export-args) | ||
911 | (with-current-buffer buf | ||
912 | (apply #'call-process-region | ||
913 | (point-min) | ||
914 | (point-max) | ||
915 | (car clipboard-html-copy-program) | ||
916 | nil ; don't delete text | ||
917 | nil ; discard the output | ||
918 | nil ; don't redisplay | ||
919 | (cdr clipboard-html-copy-program)) | ||
920 | (kill-buffer-and-window)) | ||
921 | (message "HTML copied to clipboard."))) | ||
922 | |||
923 | ;; Wayland version.. TODO: make it work for both | ||
924 | ;; (defun org-to-html-to-clipboard (&rest org-export-args) | ||
925 | ;; "Export current org buffer to HTML, then copy it to the clipboard. | ||
926 | ;; ORG-EXPORT-ARGS are passed to `org-export-to-file'." | ||
927 | ;; (let ((buf (generate-new-buffer "*org-html-clipboard*" t))) | ||
928 | ;; (apply #'org-export-to-buffer 'html buf org-export-args) | ||
929 | ;; (with-current-buffer buf | ||
930 | ;; (call-process-region (point-min) (point-max) | ||
931 | ;; "wl-copy" nil nil nil | ||
932 | ;; "-t" "text/html") | ||
933 | ;; (kill-buffer-and-window)) | ||
934 | ;; (message "HTML copied to clipboard."))) | ||
935 | |||
936 | (defun org-subtree-to-html-to-clipboard () | ||
937 | "Export current subtree to HTML." | ||
938 | (interactive) | ||
939 | (org-export-html-copy nil :subtree)) | ||
940 | |||
941 | (undohist-initialize) | ||
942 | |||
943 | (require 'hungry-delete) | ||
944 | (setopt hungry-delete-chars-to-skip " \t" | ||
945 | hungry-delete-skip-regexp (format "[%s]" hungry-delete-chars-to-skip) | ||
946 | hungry-delete-join-reluctantly nil) | ||
947 | (add-to-list 'hungry-delete-except-modes 'eshell-mode) | ||
948 | (add-to-list 'hungry-delete-except-modes 'nim-mode) | ||
949 | (add-to-list 'hungry-delete-except-modes 'python-mode) | ||
950 | (global-hungry-delete-mode) | ||
951 | |||
952 | (setopt avy-background t | ||
953 | avy-keys (string-to-list "asdfghjklqwertyuiopzxcvbnm")) | ||
954 | (keymap-global-set "M-j" #'avy-goto-char-timer) | ||
955 | (keymap-set isearch-mode-map "M-j" #'avy-isearch) | ||
956 | (keymap-global-set "M-z" #'zzz-to-char) | ||
957 | |||
958 | (marginalia-mode) | ||
959 | |||
960 | (keymap-global-set "C-x b" #'consult-buffer) | ||
961 | (keymap-global-set "C-x 4 b" #'consult-buffer-other-window) | ||
962 | (keymap-global-set "C-x 5 b" #'consult-buffer-other-frame) | ||
963 | (keymap-global-set "C-x r b" #'consult-bookmark) | ||
964 | (keymap-global-set "M-y" #'consult-yank-pop) | ||
965 | (keymap-global-set "M-g g" #'consult-goto-line) | ||
966 | (keymap-global-set "M-g M-g" #'consult-goto-line) | ||
967 | (keymap-global-set "M-g o" #'consult-outline) | ||
968 | (keymap-global-set "M-g m" #'consult-mark) | ||
969 | (keymap-global-set "M-g i" #'consult-imenu) | ||
970 | (keymap-global-set "M-s d" #'consult-find) | ||
971 | (keymap-global-set "M-s D" #'consult-locate) | ||
972 | (keymap-global-set "M-s g" #'consult-grep) | ||
973 | (keymap-global-set "M-s G" #'consult-git-grep) | ||
974 | (keymap-global-set "M-s r" #'consult-ripgrep) | ||
975 | (keymap-global-set "M-s l" #'consult-line) | ||
976 | (keymap-global-set "M-s k" #'consult-keep-lines) | ||
977 | (keymap-global-set "M-s u" #'consult-focus-lines) | ||
978 | |||
979 | (keymap-global-set "M-s e" #'consult-isearch-history) | ||
980 | (keymap-set isearch-mode-map "M-e" #'consult-isearch-history) | ||
981 | (keymap-set isearch-mode-map "M-s e" #'consult-isearch-history) | ||
982 | (keymap-set isearch-mode-map "M-s l" #'consult-line) | ||
983 | |||
984 | (keymap-set minibuffer-local-map "M-n" #'consult-history) | ||
985 | (keymap-set minibuffer-local-map "M-p" #'consult-history) | ||
986 | |||
987 | (setopt completion-in-region-function #'consult-completion-in-region | ||
988 | xref-show-xrefs-function #'consult-xref | ||
989 | xref-show-definitions-function #'consult-xref) | ||
990 | |||
991 | (setopt initial-scratch-message ";;; Emacs!\n\n") | ||
992 | |||
993 | (keymap-global-set "C-x C-b" #'ibuffer) | ||
994 | (add-hook 'ibuffer-hook #'hl-line-mode) | ||
995 | |||
996 | (require 'scule) | ||
997 | (keymap-global-set "M-c" scule-map) | ||
998 | (autoload 'titlecase-dwim "titlecase" nil t) | ||
999 | (keymap-set scule-map "M-t" #'titlecase-dwim) | ||
1000 | |||
1001 | ;; Use M-u for prefix keys | ||
1002 | (keymap-global-set "M-u" #'universal-argument) | ||
1003 | (keymap-set universal-argument-map "M-u" #'universal-argument-more) | ||
1004 | |||
1005 | (autoload 'frowny-mode "frowny" nil t) | ||
1006 | (add-hook 'jabber-chat-mode-hook #'frowny-mode) | ||
1007 | (add-hook 'jabber-chat-mode-hook #'electric-pair-local-mode-disable) | ||
1008 | |||
1009 | (autoload 'hippie-completing-read "hippie-completing-read" nil t) | ||
1010 | (keymap-global-set "M-/" #'hippie-completing-read) | ||
1011 | |||
1012 | (setopt mode-line-bell-flash-time 0.25) | ||
1013 | (autoload 'mode-line-bell-mode "mode-line-bell" nil t) | ||
1014 | (mode-line-bell-mode) | ||
1015 | |||
1016 | (keymap-global-set "C-x C-k" #'kill-this-buffer) | ||
1017 | |||
1018 | (require 'anzu) | ||
1019 | (global-anzu-mode) | ||
1020 | (setopt search-default-mode t | ||
1021 | anzu-mode-lighter "" | ||
1022 | anzu-deactivate-region t) | ||
1023 | |||
1024 | (global-set-key [remap query-replace] #'anzu-query-replace-regexp) | ||
1025 | (global-set-key [remap query-replace-regexp] #'anzu-query-replace) | ||
1026 | (define-key isearch-mode-map [remap isearch-query-replace] | ||
1027 | #'anzu-isearch-query-replace-regexp) | ||
1028 | (define-key isearch-mode-map [remap isearch-query-replace-regexp] | ||
1029 | #'anzu-isearch-query-replace) | ||